Câu trả lời:
Không phải vì nó không có ý nghĩa; nó có ý nghĩa hoàn hảo để định nghĩa "x ++" là "x + = 1, đánh giá ràng buộc trước đó của x".
Nếu bạn muốn biết lý do ban đầu, bạn sẽ phải lội qua các danh sách gửi thư cũ của Python hoặc hỏi ai đó đã ở đó (ví dụ: Guido), nhưng thật dễ dàng để biện minh sau thực tế:
Tăng và giảm đơn giản không cần nhiều như trong các ngôn ngữ khác. Bạn không viết những thứ như for(int i = 0; i < 10; ++i)
trong Python rất thường xuyên; thay vì bạn làm những việc như thế for i in range(0, 10)
.
Vì nó không cần thiết gần như thường xuyên, nên có ít lý do hơn để cung cấp cho nó cú pháp đặc biệt của riêng nó; khi bạn cần tăng, +=
thường là tốt.
Đó không phải là một quyết định về việc liệu nó có ý nghĩa hay không, hay liệu nó có thể được thực hiện hay không - và nó có thể. Đó là một câu hỏi về việc liệu lợi ích có đáng để thêm vào cú pháp cốt lõi của ngôn ngữ. Hãy nhớ rằng, đây là bốn toán tử - postinc, postdec, preinc, preec, và mỗi trong số chúng sẽ cần phải có quá tải lớp riêng; tất cả chúng cần được chỉ định, và thử nghiệm; nó sẽ thêm opcodes vào ngôn ngữ (ngụ ý một công cụ VM lớn hơn và do đó chậm hơn); mỗi lớp hỗ trợ gia tăng logic sẽ cần phải thực hiện chúng (trên đầu trang +=
và -=
).
Đây là tất cả dư thừa với +=
và -=
, vì vậy nó sẽ trở thành một khoản lỗ ròng.
i
trực tiếp - nếu bạn thực sự cần nó và không thể chỉ sử dụngarray.append()
i++
và ++i
...
++
và --
được sử dụng theo cách dẫn đến không xác định hoặc không xác định hành vi. Họ làm cho nó có thể viết mã phân tích phức tạp, khó chính xác.
Câu trả lời ban đầu mà tôi đã viết là một huyền thoại từ văn hóa dân gian về điện toán : được Dennis Ritchie gỡ lỗi là "không thể về mặt lịch sử" như đã lưu ý trong các bức thư gửi cho các biên tập viên của Truyền thông ACM tháng 7 năm 2012 : 10.1145 / 2209249.2209251
Các toán tử tăng / giảm C được phát minh tại thời điểm trình biên dịch C không thông minh lắm và các tác giả muốn có thể chỉ định mục đích trực tiếp rằng một toán tử ngôn ngữ máy nên được sử dụng để lưu một số chu kỳ cho trình biên dịch có thể làm một
load memory
load 1
add
store memory
thay vì
inc memory
và PDP-11 thậm chí còn hỗ trợ các hướng dẫn "tự động tăng tốc" và "tự động hoãn lại" tương ứng với *++p
và *p++
, tương ứng. Xem phần 5.3 của hướng dẫn nếu tò mò khủng khiếp.
Vì trình biên dịch đủ thông minh để xử lý các thủ thuật tối ưu hóa cấp cao được tích hợp theo cú pháp của C, giờ đây chúng chỉ là một tiện ích cú pháp.
Python không có thủ thuật để truyền đạt ý định cho trình biên dịch vì nó không sử dụng.
Tôi luôn cho rằng nó phải làm với dòng zen của python:
Nên có một - và tốt nhất là chỉ có một - cách rõ ràng để làm điều đó.
x ++ và x + = 1 làm cùng một điều chính xác, vì vậy không có lý do gì để có cả hai.
one--
bằng không?
one--
là một trong câu, nhưng không ngay sau đó. Vì vậy, 'công án' này cũng gợi ý rằng các toán tử tăng / giảm là không rõ ràng.
Tất nhiên, chúng ta có thể nói "Guido chỉ quyết định theo cách đó", nhưng tôi nghĩ câu hỏi thực sự là về lý do cho quyết định đó. Tôi nghĩ rằng có một số lý do:
Bởi vì, trong Python, số nguyên là bất biến (int's + = thực sự trả về một đối tượng khác).
Ngoài ra, với ++ / - bạn cần phải lo lắng về việc tăng / giảm sau so với sau tăng và chỉ cần thêm một lần nhấn phím để viết x+=1
. Nói cách khác, nó tránh được sự nhầm lẫn tiềm ẩn với chi phí thu được rất ít.
42++
... Một cái gì đó như thế này (sửa đổi một hằng số theo nghĩa đen) đã thực sự có thể trong một số trình biên dịch Fortran cũ (hoặc vì vậy tôi đã đọc): Tất cả các mục đích sử dụng trong tương lai nghĩa đen trong chương trình đó sẽ thực sự có giá trị khác. Chúc mừng gỡ lỗi!
int
s nói chung là bất biến. Một int
trong C chỉ đơn giản là chỉ định một vị trí trong bộ nhớ. Và các bit ở nơi đó là rất nhiều đột biến. Ví dụ, bạn có thể tạo một tham chiếu của một int
và thay đổi tham chiếu của tham chiếu đó. Thay đổi này có thể nhìn thấy trong tất cả các tham chiếu (bao gồm cả int
biến ban đầu ) đến địa điểm đó. Điều tương tự không giữ cho một đối tượng số nguyên Python.
Python rất nhiều về sự rõ ràng và không có lập trình viên nào có thể đoán chính xác ý nghĩa của --a
trừ khi họ đã học một ngôn ngữ có cấu trúc đó.
Python cũng rất nhiều về việc tránh các cấu trúc mời các lỗi và các ++
toán tử được biết đến là nguồn lỗi phong phú. Hai lý do này là không đủ để có các toán tử đó trong Python.
Quyết định mà Python sử dụng thụt lề để đánh dấu các khối thay vì các phương tiện cú pháp như một số hình thức bắt đầu / kết thúc hoặc đánh dấu kết thúc bắt buộc chủ yếu dựa trên cùng các cân nhắc.
Để minh họa, hãy xem cuộc thảo luận xung quanh việc giới thiệu một toán tử có điều kiện (trong C cond ? resultif : resultelse
:) cho Python vào năm 2005. Đọc ít nhất tin nhắn đầu tiên và thông điệp quyết định của cuộc thảo luận đó (có một số tiền thân về cùng một chủ đề trước đó).
Thông tin bên lề: PEP thường được đề cập trong đó là "Đề xuất mở rộng Python" PEP 308 . LC có nghĩa là hiểu danh sách , GE có nghĩa là biểu thức trình tạo (và đừng lo lắng nếu những điều đó làm bạn bối rối, chúng không phải là một trong số ít các điểm phức tạp của Python).
Hiểu biết của tôi về lý do tại sao python không có ++
toán tử theo sau: Khi bạn viết điều này trong python, a=b=c=1
bạn sẽ nhận được ba biến (nhãn) trỏ vào cùng một đối tượng (giá trị là 1). Bạn có thể xác minh điều này bằng cách sử dụng chức năng id sẽ trả về địa chỉ bộ nhớ đối tượng:
In [19]: id(a)
Out[19]: 34019256
In [20]: id(b)
Out[20]: 34019256
In [21]: id(c)
Out[21]: 34019256
Tất cả ba biến (nhãn) trỏ đến cùng một đối tượng. Bây giờ tăng một trong các biến và xem nó ảnh hưởng đến địa chỉ bộ nhớ như thế nào:
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
Bạn có thể thấy biến đó a
bây giờ trỏ đến một đối tượng khác là các biến b
và c
. Bởi vì bạn đã sử dụng a = a + 1
nó rõ ràng rõ ràng. Nói cách khác, bạn gán hoàn toàn một đối tượng khác cho nhãn a
. Hãy tưởng tượng rằng bạn có thể viết a++
nó sẽ gợi ý rằng bạn không gán cho a
đối tượng mới thay đổi mà ratter tăng đối tượng cũ. Tất cả những thứ này là IMHO để giảm thiểu nhầm lẫn. Để hiểu rõ hơn, hãy xem cách các biến python hoạt động:
Là Python gọi theo giá trị hoặc gọi theo tham chiếu? Cũng không.
Python vượt qua giá trị hay tham chiếu?
Là Python pass-by-Reference hay pass-by-value?
Python: Làm thế nào để tôi vượt qua một biến bằng cách tham chiếu?
Hiểu các biến Python và Quản lý bộ nhớ
Mô phỏng hành vi vượt qua giá trị trong python
Nó chỉ được thiết kế theo cách đó. Toán tử tăng và giảm chỉ là các phím tắt cho x = x + 1
. Python thường áp dụng chiến lược thiết kế nhằm giảm số lượng phương tiện thay thế để thực hiện một thao tác. Nhiệm vụ tăng cường là thứ gần nhất với các toán tử tăng / giảm trong Python và chúng thậm chí không được thêm cho đến Python 2.0.
return a[i++]
bằng return a[i=i+1]
.
Tôi rất mới với python nhưng tôi nghi ngờ lý do là vì sự nhấn mạnh giữa các đối tượng có thể thay đổi và bất biến trong ngôn ngữ. Bây giờ, tôi biết rằng x ++ có thể dễ dàng được hiểu là x = x + 1, nhưng nó LOOKS giống như bạn đang gia tăng tại chỗ một đối tượng có thể là bất biến.
Chỉ là phỏng đoán / cảm giác / linh cảm của tôi.
x++
gần với x += 1
hơn x = x + 1
, hai điều này tạo ra sự khác biệt cũng như trên các đối tượng có thể thay đổi.
Đầu tiên, Python chỉ bị ảnh hưởng gián tiếp bởi C; nó bị ảnh hưởng nặng nề bởi ABC , dường như không có các toán tử này , vì vậy cũng không có gì đáng ngạc nhiên khi không tìm thấy chúng trong Python.
Thứ hai, như những người khác đã nói, tăng và giảm được hỗ trợ bởi +=
và -=
đã.
Thứ ba, hỗ trợ đầy đủ cho bộ ++
và --
toán tử thường bao gồm hỗ trợ cả phiên bản tiền tố và hậu tố của chúng. Trong C và C ++, điều này có thể dẫn đến tất cả các loại cấu trúc "đáng yêu" dường như (đối với tôi) chống lại tinh thần đơn giản và thẳng thắn mà Python nắm lấy.
Ví dụ, trong khi câu lệnh C while(*t++ = *s++);
có vẻ đơn giản và thanh lịch đối với một lập trình viên có kinh nghiệm, với một người học nó, nó là bất cứ điều gì nhưng đơn giản. Ném vào một hỗn hợp của tăng và giảm tiền tố và hậu tố, và thậm chí nhiều ưu điểm sẽ phải dừng lại và suy nghĩ một chút.
Tôi tin rằng nó bắt nguồn từ tín ngưỡng Python rằng "rõ ràng là tốt hơn ngầm".
Điều này có thể là do @GlennMaynard đang xem xét vấn đề so với các ngôn ngữ khác, nhưng trong Python, bạn làm mọi thứ theo cách trăn. Đó không phải là một câu hỏi "tại sao". Nó ở đó và bạn có thể làm mọi thứ với cùng hiệu quả x+=
. Trong The Zen of Python , nó được đưa ra: "chỉ nên có một cách để giải quyết vấn đề". Nhiều lựa chọn là tuyệt vời trong nghệ thuật (tự do ngôn luận) nhưng tệ hại trong kỹ thuật.
Các ++
lớp của toán tử là biểu thức với tác dụng phụ. Đây là một cái gì đó thường không tìm thấy trong Python.
Vì lý do tương tự, một bài tập không phải là một biểu thức trong Python, do đó ngăn chặn if (a = f(...)) { /* using a here */ }
thành ngữ chung .
Cuối cùng tôi nghi ngờ rằng có toán tử không phù hợp lắm với ngữ nghĩa tham chiếu của Pythons. Hãy nhớ rằng, Python không có biến (hoặc con trỏ) với ngữ nghĩa được biết đến từ C / C ++.
f(a)
nơi a
là một danh sách, một số đối tượng không thay đổi.
Có lẽ một câu hỏi tốt hơn sẽ là hỏi tại sao các toán tử này tồn tại trong C. K & R gọi các toán tử tăng và giảm 'bất thường' (Phần 2.8 trang 46). Giới thiệu gọi chúng là 'ngắn gọn hơn và thường hiệu quả hơn'. Tôi nghi ngờ rằng thực tế là các hoạt động này luôn xuất hiện trong thao tác con trỏ cũng đã đóng một phần trong phần giới thiệu của chúng. Trong Python, có lẽ đã quyết định rằng sẽ không có ý nghĩa gì khi cố gắng tối ưu hóa gia số (thực tế tôi mới thực hiện một thử nghiệm trong C và có vẻ như hội đồng tạo gcc sử dụng addl thay vì bao gồm cả hai trường hợp) và không có con trỏ số học; vì vậy nó sẽ chỉ là một cách khác để làm điều đó và chúng ta biết Python ghê tởm điều đó.
vì tôi hiểu nó nên bạn sẽ không nghĩ giá trị trong bộ nhớ bị thay đổi. trong c khi bạn làm x ++, giá trị của x trong bộ nhớ thay đổi. nhưng trong python tất cả các số là bất biến do đó địa chỉ mà x chỉ là vẫn không có x + 1. Khi bạn viết x ++, bạn sẽ nghĩ rằng x thay đổi những gì thực sự xảy ra là x điều chỉnh được thay đổi thành một vị trí trong bộ nhớ trong đó x + 1 được lưu trữ hoặc tạo lại vị trí này nếu không tồn tại.
++
và khác với += 1
?
Để hoàn thành câu trả lời tốt trên trang đó:
Giả sử chúng ta quyết định làm điều này, tiền tố ( ++i
) sẽ phá vỡ các toán tử + và - unary.
Ngày nay, tiền tố bằng ++
hoặc --
không làm gì cả, vì nó cho phép toán tử unary plus hai lần (không làm gì) hoặc trừ unary hai lần (hai lần: tự hủy)
>>> i=12
>>> ++i
12
>>> --i
12
Vì vậy, nó có khả năng phá vỡ logic đó.
Các câu trả lời khác đã mô tả lý do tại sao nó không cần thiết cho các trình vòng lặp, nhưng đôi khi nó rất hữu ích khi gán để tăng một biến trong dòng, bạn có thể đạt được hiệu ứng tương tự bằng cách sử dụng bộ dữ liệu và nhiều phép gán:
b = ++a
trở thành:
a,b = (a+1,)*2
và b = a++
trở thành:
a,b = a+1, a
Python 3.8 giới thiệu :=
toán tử gán , cho phép chúng ta đạt được foo(++a)
với
foo(a:=a+1)
foo(a++)
vẫn còn khó nắm bắt
Tôi nghĩ rằng điều này liên quan đến các khái niệm về tính đột biến và tính bất biến của các đối tượng. 2,3,4,5 là bất biến trong trăn. Tham khảo hình ảnh dưới đây. 2 đã cố định id cho đến khi quá trình python này.
x ++ về cơ bản có nghĩa là gia tăng tại chỗ như C. Trong C, x ++ thực hiện gia số tại chỗ. Vì vậy, x = 3 và x ++ sẽ tăng 3 trong bộ nhớ lên 4, không giống như python trong đó 3 vẫn tồn tại trong bộ nhớ.
Do đó, trong python, bạn không cần tạo lại giá trị trong bộ nhớ. Điều này có thể dẫn đến tối ưu hóa hiệu suất.
Đây là một câu trả lời dựa trên linh cảm.
Tôi biết đây là một luồng cũ, nhưng trường hợp sử dụng phổ biến nhất cho ++ i không được đề cập, đó là các bộ chỉ mục thủ công khi không có chỉ mục được cung cấp. Tình huống này là lý do tại sao python cung cấp liệt kê ()
Ví dụ: Trong bất kỳ ngôn ngữ nào, khi bạn sử dụng cấu trúc như foreach để lặp lại một tập hợp - vì lợi ích của ví dụ, chúng tôi thậm chí sẽ nói đó là một tập hợp không có thứ tự và bạn cần một chỉ mục duy nhất cho mọi thứ để phân biệt chúng, nói
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
Trong trường hợp như thế này, python cung cấp một phương thức liệt kê, ví dụ
for i, (key, val) in enumerate(stuff.items()) :