Mengapa tidak ada operator ++ dan - di Python?

442

Mengapa tidak ada ++dan --operator di Python?

Leonid
sumber
karena ada redunden
cmarangu
Ada 4 operator ++ berbeda yang semuanya melakukan hal yang sama. Oh dan di sana menghapus "++" dari "C ++" sekarang yang tampak seperti degenerasi
cmarangu

Jawaban:

443

Itu bukan karena itu tidak masuk akal; masuk akal untuk mendefinisikan "x ++" sebagai "x + = 1, mengevaluasi ke pengikatan x sebelumnya".

Jika Anda ingin mengetahui alasan aslinya, Anda harus mengarungi milis Python lama atau bertanya kepada seseorang yang ada di sana (mis. Guido), tetapi cukup mudah untuk membenarkan setelah fakta:

Peningkatan dan penurunan sederhana tidak diperlukan sebanyak dalam bahasa lain. Anda tidak sering menulis hal-hal seperti for(int i = 0; i < 10; ++i)di Python; alih-alih Anda melakukan hal-hal seperti for i in range(0, 10).

Karena itu tidak diperlukan hampir sesering mungkin, ada jauh lebih sedikit alasan untuk memberikan sintaksisnya sendiri; ketika Anda perlu kenaikan, +=biasanya baik-baik saja.

Itu bukan keputusan apakah itu masuk akal, atau apakah itu bisa dilakukan - ya, dan itu bisa. Ini pertanyaan apakah manfaatnya layak ditambahkan ke sintaks inti bahasa. Ingat, ini adalah empat operator - postinc, postdec, preinc, predec, dan masing-masing operator perlu memiliki kelas yang berlebih; mereka semua harus ditentukan, dan diuji; itu akan menambahkan opcodes ke bahasa (menyiratkan mesin VM yang lebih besar, dan karena itu lebih lambat); setiap kelas yang mendukung peningkatan logis perlu mengimplementasikannya (di atas +=dan -=).

Ini semua berlebihan dengan +=dan -=, jadi itu akan menjadi rugi bersih.

Glenn Maynard
sumber
98
Sering berguna untuk menggunakan sesuatu seperti array [i ++], yang tidak rapi dilakukan dengan + = / - =.
Turner Hayes
102
@thayes: Itu bukan pola umum di Python.
Glenn Maynard
9
@thayes Karena itu akan berada di dalam satu loop, Anda mungkin juga loop ilangsung - jika Anda benar-benar membutuhkannya dan tidak bisa hanya menggunakan misalnyaarray.append()
Tobias Kienzler
31
Saya melihat keprihatinan yang jauh lebih besar adalah keterbacaan dan prediktabilitas. Kembali di hari C saya, saya melihat lebih dari cukup bug yang berasal dari kesalahpahaman tentang perbedaan antara i++dan ++i...
Charles Duffy
5
Menambah justifikasi setelah-fakta: pada proyek yang saya kerjakan, saya telah menemui (lebih dari siapa pun dalam hidup mereka) sejumlah kode C ++ yang mengalami masalah dengan ++dan --digunakan dengan cara yang menghasilkan tidak ditentukan atau tidak ditentukan tingkah laku. Mereka memungkinkan untuk menulis kode yang rumit, sulit diurai dengan benar.
Brian Vandenberg
84

Jawaban asli yang saya tulis ini adalah mitos dari cerita rakyat komputasi : dibantah oleh Dennis Ritchie sebagai "secara historis tidak mungkin" seperti yang tercantum dalam surat kepada editor Komunikasi ACM Juli 2012 doi: 10.1145 / 2209249.2209251


Operator kenaikan / penurunan C ditemukan pada saat ketika kompiler C tidak terlalu pintar dan penulis ingin dapat menentukan maksud langsung bahwa operator bahasa mesin harus digunakan yang menyimpan beberapa siklus untuk kompiler yang mungkin melakukan a

load memory
load 1
add
store memory

dari pada

inc memory 

dan PDP-11 bahkan didukung "autoincrement" dan "autoincrement ditangguhkan" petunjuk sesuai dengan *++pdan *p++masing-masing. Lihat bagian 5.3 manual jika penasaran.

Karena kompiler cukup pintar untuk menangani trik optimasi tingkat tinggi yang dibangun ke dalam sintaks C, mereka hanyalah kenyamanan sintaksis sekarang.

Python tidak memiliki trik untuk menyampaikan maksud kepada assembler karena tidak menggunakannya.

msw
sumber
4
Javascript memiliki ++. Saya tidak berpikir itu "trik untuk menyampaikan niat kepada assembler." Plus, Python memang memiliki bytecode. Jadi saya pikir alasannya adalah hal lain.
Nathan Davis
13
Ini bisnis "memberikan petunjuk kepada kompiler" memang mitos. Terus terang, ini adalah tambahan bodoh untuk bahasa apa pun dan melanggar dua sila berikut: 1. Anda tidak membuat kode untuk dibaca komputer, Anda memberi kode untuk dibaca oleh insinyur lain. Dan 2. Anda tidak membaca kode untuk insinyur yang kompeten untuk membaca, Anda kode untuk insinyur yang kompeten untuk membaca saat kelelahan pukul 3 pagi dan melompat pada kafein.
3
@ tgm1024 Agar adil, saat mengkode pada 10–30 karakter per detik, setengah-dupleks teletype, kode Anda sehingga Anda dapat memasukkannya sebelum minggu depan.
msw
4
@ tgm1024 Unix dan C melihat sebagian besar pengembangan awal mereka pada PDP-11 yang menggunakan teletype yang sangat lambat untuk komunikasi pengguna. Meskipun Anda benar bahwa hari ini pengkodean untuk mesin sebagian besar konyol, saat itu antarmuka Manusia / Mesin yang merupakan hambatan. Sulit membayangkan bekerja perlahan jika Anda tidak perlu melakukannya.
msw
65

Saya selalu menganggap itu ada hubungannya dengan baris zen dari python ini:

Seharusnya ada satu - dan lebih disukai hanya satu - cara yang jelas untuk melakukannya.

x ++ dan x + = 1 melakukan hal yang persis sama, jadi tidak ada alasan untuk memiliki keduanya.

GSto
sumber
10
one--adalah nol?
Andre Holzner
25
one--adalah satu dalam kalimat, tetapi nol segera setelahnya. Jadi 'koan' ini juga mengisyaratkan bahwa operator kenaikan / penurunan tidak jelas.
Victor K
14
@EralpB Jika Anda menghapus + =, maka Anda tidak dapat melakukan hal-hal seperti x + = 10. + = adalah kasus yang lebih umum dari ++
Rory
8
Juga: "Eksplisit lebih baik daripada implisit".
Ber
2
Jelas tidak sama, karena x + = 1 BUKAN ekspresi - ini adalah pernyataan - dan tidak mengevaluasi apa pun. Anda tidak dapat melakukan hal-hal seperti: 'baris [col ++] = a; baris [col ++] = b '. Belum lagi hal-hal pre-inc dan post-inc yang dimiliki c ++.
Uri
38

Tentu saja, kita dapat mengatakan "Guido baru saja memutuskan seperti itu", tetapi saya pikir pertanyaannya adalah tentang alasan keputusan itu. Saya pikir ada beberapa alasan:

  • Ini menggabungkan pernyataan dan ungkapan, yang bukan praktik yang baik. Lihat http://norvig.com/python-iaq.html
  • Ini umumnya mendorong orang untuk menulis kode yang kurang mudah dibaca
  • Kompleksitas ekstra dalam implementasi bahasa, yang tidak perlu dalam Python, seperti yang telah disebutkan
EMP
sumber
12
Senang seseorang akhirnya menyebutkan aspek pernyataan vs ekspresi. Dalam tugas C adalah ekspresi dan operator ++. Dalam penugasan Python adalah pernyataan, jadi jika memiliki ++, itu kemungkinan akan perlu menjadi pernyataan penugasan juga (dan bahkan kurang berguna atau dibutuhkan).
martineau
Setuju - jika itu adalah pernyataan, maka paling tidak akan menjadi sama sekali tidak berarti untuk berbicara tentang perbedaan antara pasca dan pra-operator.
Crowman
17

Karena, dalam Python, integer tidak dapat diubah (int's + = sebenarnya mengembalikan objek yang berbeda).

Juga, dengan ++ / - Anda perlu khawatir tentang sebelum / sesudah kenaikan / penurunan, dan hanya perlu satu tombol lagi untuk menulis x+=1. Dengan kata lain, itu menghindari potensi kebingungan dengan mengorbankan sangat sedikit keuntungan.

Nathan Davis
sumber
int juga tidak dapat diubah dalam C. Jika Anda tidak berpikir begitu, cobalah untuk mendapatkan C compiler untuk menghasilkan kode untuk 42++... Sesuatu seperti ini (memodifikasi konstan literal) itu benar-benar mungkin dalam beberapa kompiler Fortran lama (atau jadi saya sudah membaca): Semua penggunaan masa depan dari literal dalam menjalankan program maka akan benar-benar memiliki nilai yang berbeda. Selamat men-debug!
Lutz Prechelt
10
Baik. 42 adalah konstanta literal . Konstanta (atau setidaknya harus ) tidak berubah. Itu tidak berarti C intsecara umum tidak dapat diubah. Sebuah intdi C hanya menunjukkan tempat di memori. Dan bit di tempat itu sangat bisa berubah. Anda dapat, misalnya, membuat referensi dari intdan mengubah referensi dari referensi itu. Perubahan ini terlihat di semua referensi (termasuk intvariabel asli ) ke tempat itu. Hal yang sama tidak berlaku untuk objek integer Python.
Nathan Davis
x + = 1 tidak berakhir menjadi inc mem. Python mengeksekusi panggilan fungsi untuk menambahkan 1 ke variabel; itu menyedihkan.
PalaDolphin
12

Kejelasan!

Python banyak tentang kejelasan dan tidak ada programmer yang mungkin menebak dengan benar arti --akecuali dia belajar bahasa yang memiliki konstruksi itu.

Python juga banyak tentang menghindari konstruksi yang mengundang kesalahan dan ++operator dikenal sebagai sumber cacat yang kaya. Dua alasan ini cukup untuk tidak memiliki operator di Python.

Keputusan bahwa Python menggunakan lekukan untuk menandai blok daripada cara sintaksis seperti beberapa bentuk bracketing mulai / akhir atau penandaan akhir wajib sebagian besar didasarkan pada pertimbangan yang sama.

Untuk ilustrasi, kita lihat di diskusi sekitar memperkenalkan operator kondisional (di C: cond ? resultif : resultelse) ke Python pada tahun 2005. Baca setidaknya pesan pertama dan pesan keputusan itu diskusi (yang memiliki beberapa prekursor pada topik yang sama sebelumnya).

Trivia: PEP yang sering disebutkan di sini adalah "Python Extension Proposal" PEP 308 . LC berarti pemahaman daftar , GE berarti ekspresi generator (dan jangan khawatir jika itu membingungkan Anda, mereka bukan satu-satunya dari beberapa titik rumit Python).

Lutz Prechelt
sumber
10

Pemahaman saya tentang mengapa python tidak memiliki ++operator adalah sebagai berikut: Ketika Anda menulis ini dengan python a=b=c=1Anda akan mendapatkan tiga variabel (label) menunjuk pada objek yang sama (yang nilainya 1). Anda dapat memverifikasi ini dengan menggunakan fungsi id yang akan mengembalikan alamat memori objek:

In [19]: id(a)
Out[19]: 34019256

In [20]: id(b)
Out[20]: 34019256

In [21]: id(c)
Out[21]: 34019256

Ketiga variabel (label) menunjuk ke objek yang sama. Sekarang tambahkan salah satu variabel dan lihat bagaimana hal itu memengaruhi alamat memori:

In [22] a = a + 1

In [23]: id(a)
Out[23]: 34019232

In [24]: id(b)
Out[24]: 34019256

In [25]: id(c)
Out[25]: 34019256

Anda dapat melihat variabel itu asekarang menunjuk ke objek lain sebagai variabel bdan c. Karena Anda telah menggunakannya a = a + 1jelas secara eksplisit. Dengan kata lain Anda menetapkan sepenuhnya objek lain untuk diberi label a. Bayangkan bahwa Anda dapat menulis a++itu akan menyarankan bahwa Anda tidak menugaskan objek variabel abaru tetapi kenaikan ratter yang lama. Semua ini adalah IMHO untuk meminimalkan kebingungan. Untuk pemahaman yang lebih baik, lihat cara kerja variabel python:

Dalam Python, mengapa suatu fungsi dapat memodifikasi beberapa argumen seperti yang dirasakan oleh pemanggil, tetapi tidak yang lain?

Apakah Python call-by-value atau call-by-reference? Tidak juga.

Apakah Python melewati nilai, atau dengan referensi?

Apakah Python pass-by-reference atau pass-by-value?

Python: Bagaimana cara saya melewatkan variabel dengan referensi?

Memahami variabel Python dan Manajemen Memori

Meniru perilaku pass-by-value dalam python

Fungsi python memanggil dengan referensi

Kode Seperti Pythonista: Python Idiomatik

Wakan Tanka
sumber
9

Itu hanya dirancang seperti itu. Operator kenaikan dan penurunan hanyalah jalan pintas untuk x = x + 1. Python biasanya mengadopsi strategi desain yang mengurangi jumlah cara alternatif melakukan operasi. Penugasan augmented adalah hal yang paling dekat dengan operator increment / decrement di Python, dan mereka bahkan tidak ditambahkan hingga Python 2.0.

Reed Copsey
sumber
3
Ya sobat, seperti, Anda bisa menggantinya return a[i++]dengan return a[i=i+1].
Luís de Sousa
7

Saya sangat baru untuk python tapi saya menduga alasannya adalah karena penekanan antara objek yang bisa berubah dan tidak berubah dalam bahasa. Sekarang, saya tahu bahwa x ++ dapat dengan mudah diartikan sebagai x = x +1, tetapi sepertinya Anda menambahkan di tempat objek yang bisa berubah.

Hanya dugaan / perasaan / dugaan saya.

mkoistinen
sumber
Dalam aspek ini, x++lebih dekat x += 1daripada daripada x = x + 1, keduanya membuat perbedaan juga pada objek yang bisa berubah.
glglgl
4

Pertama, Python hanya secara tidak langsung dipengaruhi oleh C; itu sangat dipengaruhi oleh ABC , yang tampaknya tidak memiliki operator ini , jadi seharusnya tidak menjadi kejutan besar untuk tidak menemukannya di Python juga.

Kedua, seperti yang dikatakan orang lain, kenaikan dan penurunan didukung oleh +=dan -=sudah.

Ketiga, dukungan penuh untuk ++dan --set operator biasanya mencakup mendukung versi awalan dan postfix mereka. Dalam C dan C ++, ini dapat menyebabkan semua jenis konstruksi "indah" yang tampaknya (bagi saya) bertentangan dengan semangat kesederhanaan dan keterusterangan yang dianut oleh Python.

Misalnya, sementara pernyataan C while(*t++ = *s++);mungkin tampak sederhana dan elegan untuk programmer yang berpengalaman, bagi seseorang yang mempelajarinya, itu sama sekali tidak sederhana. Lemparkan campuran kenaikan dan penurunan awalan dan postfix, dan bahkan banyak pro harus berhenti dan berpikir sedikit.

wberry
sumber
3

Saya percaya ini berasal dari pernyataan Python bahwa "eksplisit lebih baik daripada implisit".

Sepheus
sumber
Nah, Anda tidak secara eksplisit menulis pernyataan "mulai" dan "akhiri" dengan Python, kan? Meskipun saya setuju dengan pernyataan itu, saya pikir ada batasan untuk itu. Sementara kita dapat berdebat tentang batas-batas itu, saya pikir kita semua bisa setuju, bahwa ada garis, yang tidak praktis untuk dilintasi. Dan karena ada begitu banyak pendapat dan pembenaran atas keputusan itu, saya pikir itu bukan pilihan yang jelas. Setidaknya, saya tidak dapat menemukan sumber, di mana dinyatakan secara eksplisit
Hasan Ammori
3

Ini mungkin karena @GlennMaynard melihat masalah ini dibandingkan dengan bahasa lain, tetapi dengan Python, Anda melakukan berbagai hal dengan cara python. Itu bukan pertanyaan 'mengapa'. Itu ada di sana dan Anda dapat melakukan hal-hal dengan efek yang sama x+=. Dalam The Zen of Python , diberikan: "seharusnya hanya ada satu cara untuk menyelesaikan masalah." Pilihan ganda sangat bagus dalam seni (kebebasan berekspresi) tetapi buruk dalam rekayasa.

Nihal Sahu
sumber
2

The ++kelas operator adalah ekspresi dengan efek samping. Ini adalah sesuatu yang umumnya tidak ditemukan dengan Python.

Untuk alasan yang sama tugas bukanlah ekspresi dalam Python, sehingga mencegah if (a = f(...)) { /* using a here */ }idiom umum .

Terakhir saya curiga ada operator yang tidak terlalu konsisten dengan semantik referensi Python. Ingat, Python tidak memiliki variabel (atau pointer) dengan semantik yang diketahui dari C / C ++.

Ber
sumber
1
tidak ada yang mencegah memanggil fungsi dengan efek samping dalam tes / ekspresi / daftar pemahaman: di f(a)mana adaftar, beberapa objek yang tidak dapat diubah.
Jean-François Fabre
1

Mungkin pertanyaan yang lebih baik adalah untuk bertanya mengapa operator ini ada di C. K&R menyebut operator kenaikan dan penurunan 'tidak biasa' (Bagian 2.8 halaman 46). Pendahuluan menyebut mereka 'lebih ringkas dan sering lebih efisien'. Saya menduga bahwa fakta bahwa operasi ini selalu muncul dalam manipulasi pointer juga telah berperan dalam pengantar mereka. Dalam Python mungkin telah diputuskan bahwa tidak masuk akal untuk mencoba mengoptimalkan peningkatan (pada kenyataannya saya hanya melakukan tes dalam C, dan tampaknya bahwa rakitan yang dihasilkan gcc menggunakan addl bukan incl dalam kedua kasus) dan tidak ada pointer aritmatika; jadi itu akan menjadi Satu Lagi Cara untuk Melakukannya dan kita tahu Python benci itu.

Ludovico Fischer
sumber
1

seperti yang saya mengerti sehingga Anda tidak akan berpikir nilai dalam memori berubah. di c ketika Anda melakukan x ++ nilai x dalam memori berubah. tetapi dalam python semua angka tidak dapat diubah maka alamat yang x menunjuk sebagai masih memiliki x bukan x +1. ketika Anda menulis x ++ Anda akan berpikir bahwa x mengubah apa yang sebenarnya terjadi adalah bahwa x refrence diubah ke lokasi di memori di mana x +1 disimpan atau menciptakan kembali lokasi ini jika tidak ada.

rafi wiener
sumber
1
Jadi apa yang membuatnya ++berbeda dari ini += 1?
Ber
1

Untuk melengkapi jawaban yang sudah bagus di halaman itu:

Misalkan kita memutuskan untuk melakukan ini, awalan ( ++i) yang akan merusak operator + dan - unary.

Hari ini, awalan dengan ++atau --tidak melakukan apa-apa, karena memungkinkan unary plus operator dua kali (tidak melakukan apa-apa) atau unary minus dua kali (dua kali: membatalkan sendiri)

>>> i=12
>>> ++i
12
>>> --i
12

Sehingga berpotensi mematahkan logika itu.

Jean-François Fabre
sumber
1

Jawaban lain telah menjelaskan mengapa itu tidak diperlukan untuk iterator, tetapi kadang-kadang berguna ketika menugaskan untuk meningkatkan variabel in-line, Anda dapat mencapai efek yang sama menggunakan tupel dan penugasan ganda:

b = ++a menjadi:

a,b = (a+1,)*2

dan b = a++menjadi:

a,b = a+1, a

Python 3.8 memperkenalkan tugas :=operator, memungkinkan kita untuk mencapai foo(++a)dengan

foo(a:=a+1)

foo(a++) masih sulit dipahami.

JeffUK
sumber
2
: = tugas adalah aib
nehem
0

Saya pikir ini berkaitan dengan konsep mutabilitas dan kekekalan objek. 2,3,4,5 tidak berubah dalam python. Lihat gambar di bawah ini. 2 telah memperbaiki id hingga proses python ini.

ID konstanta dan variabel

x ++ pada dasarnya berarti peningkatan di tempat seperti C. Dalam C, x ++ melakukan peningkatan di tempat. Jadi, x = 3, dan x ++ akan menambah 3 di memori menjadi 4, tidak seperti python di mana 3 akan tetap ada di memori.

Jadi dengan python, Anda tidak perlu membuat ulang nilai dalam memori. Ini dapat menyebabkan optimalisasi kinerja.

Ini adalah jawaban berdasarkan firasat.

Pikesh Prasoon
sumber
0

Saya tahu ini adalah utas lama, tetapi kasus penggunaan yang paling umum untuk ++ i tidak tercakup, yaitu menjadi pengindeksan secara manual saat tidak ada indeks yang disediakan. Situasi ini adalah mengapa python menyediakan enumerate ()

Contoh: Dalam bahasa apa pun, ketika Anda menggunakan konstruksi seperti foreach untuk beralih pada set - demi contoh, kami bahkan akan mengatakan itu set unordered dan Anda perlu indeks unik untuk semuanya untuk membedakan mereka, katakan

i = 0
stuff = {'a': 'b', 'c': 'd', 'e': 'f'}
uniquestuff = {}
for key, val in stuff.items() :
  uniquestuff[key] = '{0}{1}'.format(val, i)
  i += 1

Dalam kasus seperti ini, python menyediakan metode enumerasi, misalnya

for i, (key, val) in enumerate(stuff.items()) :
Jessica Pennell
sumber