为什么没有++以及—— Python 中的运算符?
为什么Python中没有++
和--
运算符?
Why are there no ++
and --
operators in Python?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
为什么Python中没有++
和--
运算符?
Why are there no ++
and --
operators in Python?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(20)
这并不是因为它没有意义;而是因为它没有意义。将“x++”定义为“x += 1,评估 x 的先前绑定”是非常有意义的。
如果你想知道最初的原因,你必须浏览旧的 Python 邮件列表或询问那里的人(例如 Guido),但事后很容易证明:
简单的递增和递减不是与其他语言一样需要。你不会经常在 Python 中编写像
for(int i = 0; i < 10; ++i)
这样的东西;相反,您可以执行诸如for i in range(0, 10)
之类的操作。由于几乎不需要它,因此没有理由赋予它自己的特殊语法;当您确实需要增加时,
+=
通常就可以了。这不是决定它是否有意义,或者是否可以做到——它确实有效,而且可以。问题在于这种好处是否值得添加到该语言的核心语法中。请记住,这是四个运算符——postinc、postdec、preinc、predec,并且每个运算符都需要有自己的类重载;它们都需要被指定和测试;它将向该语言添加操作码(意味着更大,因此更慢的VM引擎);每个支持逻辑增量的类都需要实现它们(在
+=
和-=
之上)。这对于
+=
和-=
来说都是多余的,所以它会变成净损失。It's not because it doesn't make sense; it makes perfect sense to define "x++" as "x += 1, evaluating to the previous binding of x".
If you want to know the original reason, you'll have to either wade through old Python mailing lists or ask somebody who was there (eg. Guido), but it's easy enough to justify after the fact:
Simple increment and decrement aren't needed as much as in other languages. You don't write things like
for(int i = 0; i < 10; ++i)
in Python very often; instead you do things likefor i in range(0, 10)
.Since it's not needed nearly as often, there's much less reason to give it its own special syntax; when you do need to increment,
+=
is usually just fine.It's not a decision of whether it makes sense, or whether it can be done--it does, and it can. It's a question of whether the benefit is worth adding to the core syntax of the language. Remember, this is four operators--postinc, postdec, preinc, predec, and each of these would need to have its own class overloads; they all need to be specified, and tested; it would add opcodes to the language (implying a larger, and therefore slower, VM engine); every class that supports a logical increment would need to implement them (on top of
+=
and-=
).This is all redundant with
+=
and-=
, so it would become a net loss.我写的这个原始答案是计算民间传说中的一个神话:被 Dennis Ritchie 揭穿为“历史上不可能的”,正如在给 ACM Communications 编辑的信中指出的那样2012 年 7 月 doi:10.1145/2209249.2209251
C 递增/递减运算符是在 C 语言诞生时发明的编译器不是很聪明,作者希望能够指定应该使用机器语言运算符的直接意图,这为编译器节省了一些周期,而编译器可能会执行 a
而不是
,PDP-11 甚至支持“自动增量” ”和“自动增量延迟”指令分别对应于
*++p
和*p++
。请参阅 手册(如果非常好奇的话)。由于编译器足够智能,可以处理 C 语法中内置的高级优化技巧,因此它们现在只是一种语法上的便利。
Python 没有向汇编器传达意图的技巧,因为它不使用这种技巧。
This original answer I wrote is a myth from the folklore of computing: debunked by Dennis Ritchie as "historically impossible" as noted in the letters to the editors of Communications of the ACM July 2012 doi:10.1145/2209249.2209251
The C increment/decrement operators were invented at a time when the C compiler wasn't very smart and the authors wanted to be able to specify the direct intent that a machine language operator should be used which saved a handful of cycles for a compiler which might do a
instead of
and the PDP-11 even supported "autoincrement" and "autoincrement deferred" instructions corresponding to
*++p
and*p++
, respectively. See section 5.3 of the manual if horribly curious.As compilers are smart enough to handle the high-level optimization tricks built into the syntax of C, they are just a syntactic convenience now.
Python doesn't have tricks to convey intentions to the assembler because it doesn't use one.
我一直认为这与Python禅宗的这一行有关:
x++ 和 x+=1 执行完全相同的操作,因此没有理由同时使用两者。
I always assumed it had to do with this line of the zen of python:
x++ and x+=1 do the exact same thing, so there is no reason to have both.
当然,我们可以说“吉多就是这样决定的”,但我认为问题实际上是关于该决定的原因。我认为有几个原因:
Of course, we could say "Guido just decided that way", but I think the question is really about the reasons for that decision. I think there are several reasons:
因为,在Python中,整数是不可变的(int的+=实际上返回一个不同的对象)。
另外,使用 ++/-- 时,您需要担心前后递增/递减,并且只需要再敲一次键即可写入
x+=1
。换句话说,它以微乎其微的收益为代价,避免了潜在的混乱。Because, in Python, integers are immutable (int's += actually returns a different object).
Also, with ++/-- you need to worry about pre- versus post- increment/decrement, and it takes only one more keystroke to write
x+=1
. In other words, it avoids potential confusion at the expense of very little gain.明晰!
Python 非常注重清晰度,没有程序员可能正确猜测
--a
的含义,除非他/她学习了具有该构造的语言。Python 还非常注重避免引发错误的构造,并且
++
运算符众所周知是缺陷的丰富来源。这两个原因足以让 Python 中不使用这些运算符。
Python 使用缩进来标记块而不是
比句法手段,例如某种形式的开始/结束括号
或强制结束标记主要基于相同的考虑。
为了说明这一点,请看一下 2005 年关于在 Python 中引入条件运算符的讨论(在 C:
cond ? resultif : resultelse
中)。至少阅读第一条消息和决策消息 讨论(之前有关于同一主题的几个先驱)。
琐事:
其中经常提到的 PEP 是“Python 增强提案”PEP 308。 LC 表示 列表理解,GE 表示 生成器表达式 (如果这些让您感到困惑,请不要担心,它们都不是Python 的一些复杂点)。
Clarity!
Python is a lot about clarity and no programmer is likely to correctly guess the meaning of
--a
unless s/he's learned a language having that construct.Python is also a lot about avoiding constructs that invite mistakes and the
++
operators are known to be rich sources of defects.These two reasons are enough not to have those operators in Python.
The decision that Python uses indentation to mark blocks rather
than syntactical means such as some form of begin/end bracketing
or mandatory end marking is based largely on the same considerations.
For illustration, have a look at the discussion around introducing a conditional operator (in C:
cond ? resultif : resultelse
) into Python in 2005.Read at least the first message and the decision message of that discussion (which had several precursors on the same topic previously).
Trivia:
The PEP frequently mentioned therein is the "Python Enhancement Proposal" PEP 308. LC means list comprehension, GE means generator expression (and don't worry if those confuse you, they are none of the few complicated spots of Python).
我对为什么Python没有
++
运算符的理解如下:当你在Python中编写a=b=c=1
时,你会得到三个指向的变量(标签)在同一个对象上(其值为 1)。您可以使用 id 函数来验证这一点,该函数将返回一个对象内存地址:所有三个变量(标签)都指向同一个对象。现在增加一个变量并查看它如何影响内存地址:
您可以看到变量
a
现在作为变量b
和c
指向另一个对象。因为您已经使用了a = a + 1
,所以它是明确清晰的。换句话说,您将完全另一个对象分配给标签a
。想象一下,您可以编写a++
,这表明您没有分配给变量a
新对象,而是增加了旧对象。恕我直言,所有这些都是为了尽量减少混乱。为了更好地理解Python变量的工作原理:在 Python 中,为什么函数可以修改调用者感知到的某些参数,而不是其他参数?
Python 是按值调用还是按引用调用?
Python 是否通过按值还是按引用?
Python 是按引用传递还是按值传递?
Python:如何通过引用传递变量?
了解 Python 变量和内存管理
在 python 中模拟传值行为
Python 函数通过引用调用
像 Pythonista 一样编写代码:惯用语Python
My understanding of why python does not have
++
operator is following: When you write this in pythona=b=c=1
you will get three variables (labels) pointing at same object (which value is 1). You can verify this by using id function which will return an object memory address:All three variables (labels) point to the same object. Now increment one of variable and see how it affects memory addresses:
You can see that variable
a
now points to another object as variablesb
andc
. Because you've useda = a + 1
it is explicitly clear. In other words you assign completely another object to labela
. Imagine that you can writea++
it would suggest that you did not assign to variablea
new object but ratter increment the old one. All this stuff is IMHO for minimization of confusion. For better understanding see how python variables works:In Python, why can a function modify some arguments as perceived by the caller, but not others?
Is Python call-by-value or call-by-reference? Neither.
Does Python pass by value, or by reference?
Is Python pass-by-reference or pass-by-value?
Python: How do I pass a variable by reference?
Understanding Python variables and Memory Management
Emulating pass-by-value behaviour in python
Python functions call by reference
Code Like a Pythonista: Idiomatic Python
它就是这样设计的。递增和递减运算符只是 x = x + 1 的快捷方式。 Python 通常采用一种设计策略来减少执行操作的替代方法的数量。 增强赋值是最接近递增/递减运算符的东西在 Python 中,直到 Python 2.0 才添加它们。
It was just designed that way. Increment and decrement operators are just shortcuts for
x = x + 1
. Python has typically adopted a design strategy which reduces the number of alternative means of performing an operation. Augmented assignment is the closest thing to increment/decrement operators in Python, and they weren't even added until Python 2.0.我对 python 很陌生,但我怀疑原因是因为语言中强调可变和不可变对象。现在,我知道 x++ 可以很容易地解释为 x = x + 1,但看起来您正在就地递增一个可能不可变的对象。
只是我的猜测/感觉/预感。
I'm very new to python but I suspect the reason is because of the emphasis between mutable and immutable objects within the language. Now, I know that x++ can easily be interpreted as x = x + 1, but it LOOKS like you're incrementing in-place an object which could be immutable.
Just my guess/feeling/hunch.
为了完成该页面上已经很好的答案:
假设我们决定这样做,前缀 (
++i
) 会破坏一元 + 和 - 运算符。今天,前缀
++
或--
没有任何作用,因为它启用一元加运算符两次(不执行任何操作)或一元减运算符两次(两次:取消自身),因此可能会打破这个逻辑。
现在,如果需要列表推导式或 lambda,从 python 3.8 开始,可以使用新的
:=
赋值运算符 (PEP572)前自增
a
并赋值给b
:后自增只需补一下过早加减 1:
To complete already good answers on that page:
Let's suppose we decide to do this, prefix (
++i
) that would break the unary + and - operators.Today, prefixing by
++
or--
does nothing, because it enables unary plus operator twice (does nothing) or unary minus twice (twice: cancels itself)So that would potentially break that logic.
now if one needs it for list comprehensions or lambdas, from python 3.8 it's possible with the new
:=
assignment operator (PEP572)pre-incrementing
a
and assign it tob
:post-incrementing just needs to make up the premature add by subtracting 1:
我相信这源于Python的信条“显式优于隐式”。
I believe it stems from the Python creed that "explicit is better than implicit".
首先,Python只是间接受到C的影响;它深受 ABC 的影响,其中 显然没有这些运算符,因此在 Python 中找不到它们也不足为奇。
其次,正如其他人所说,
+=
和-=
已经支持递增和递减。第三,对
++
和--
运算符集的完全支持通常包括支持它们的前缀和后缀版本。在 C 和 C++ 中,这可能会导致各种“可爱”的结构,这些结构(在我看来)似乎违背了 Python 所推崇的简单和直接的精神。例如,虽然 C 语句
while(*t++ = *s++);
对于经验丰富的程序员来说可能看起来简单而优雅,但对于学习它的人来说,它却一点也不简单。再加上前缀和后缀增量和减量的混合,甚至许多专业人士都必须停下来思考一下。First, Python is only indirectly influenced by C; it is heavily influenced by ABC, which apparently does not have these operators, so it should not be any great surprise not to find them in Python either.
Secondly, as others have said, increment and decrement are supported by
+=
and-=
already.Third, full support for a
++
and--
operator set usually includes supporting both the prefix and postfix versions of them. In C and C++, this can lead to all kinds of "lovely" constructs that seem (to me) to be against the spirit of simplicity and straight-forwardness that Python embraces.For example, while the C statement
while(*t++ = *s++);
may seem simple and elegant to an experienced programmer, to someone learning it, it is anything but simple. Throw in a mixture of prefix and postfix increments and decrements, and even many pros will have to stop and think a bit.++
类运算符是具有副作用的表达式。这在 Python 中通常是找不到的。出于同样的原因,Python 中的赋值不是表达式,因此可以防止常见的
if (a = f(...)) { /* using a here */ }
习惯用法。最后我怀疑there运算符与Python的参考语义不太一致。请记住,Python 没有具有 C/C++ 语义的变量(或指针)。
The
++
class of operators are expressions with side effects. This is something generally not found in Python.For the same reason an assignment is not an expression in Python, thus preventing the common
if (a = f(...)) { /* using a here */ }
idiom.Lastly I suspect that there operator are not very consistent with Pythons reference semantics. Remember, Python does not have variables (or pointers) with the semantics known from C/C++.
据我理解,你不会认为内存中的值发生了变化。
在c中,当你执行x++时,内存中x的值会发生变化。
但在Python中,所有数字都是不可变的,因此x指向的地址仍然是x而不是x+1。当你编写 x++ 时,你会认为 x 发生了变化,真正发生的是 x 引用被更改为内存中存储 x+1 的位置,或者如果 doe 不存在,则重新创建该位置。
as i understood it so you won't think the value in memory is changed.
in c when you do x++ the value of x in memory changes.
but in python all numbers are immutable hence the address that x pointed as still has x not x+1. when you write x++ you would think that x change what really happens is that x refrence is changed to a location in memory where x+1 is stored or recreate this location if doe's not exists.
其他答案已经描述了为什么迭代器不需要它,但有时在分配以增加内联变量时很有用,您可以使用元组和多重赋值来达到相同的效果:
b = ++a
变为:并且
b = a++
变为:Python 3.8 引入了赋值
:=
运算符,允许我们用< 实现
foo(++a)
但 code>foo(a++) 仍然难以捉摸。Other answers have described why it's not needed for iterators, but sometimes it is useful when assigning to increase a variable in-line, you can achieve the same effect using tuples and multiple assignment:
b = ++a
becomes:and
b = a++
becomes:Python 3.8 introduces the assignment
:=
operator, allowing us to achievefoo(++a)
withfoo(a++)
is still elusive though.也许更好的问题是问为什么这些运算符存在于 C 中。K&R 称增量和减量运算符“不寻常”(第 2.8 节,第 46 页)。简介称它们“更简洁且通常更高效”。我怀疑这些操作总是出现在指针操作中这一事实也在它们的介绍中发挥了作用。
在Python中,可能已经决定尝试优化增量是没有意义的(事实上我只是在C中做了一个测试,似乎gcc生成的程序集在这两种情况下都使用addl而不是incl)并且没有指针算术;所以这只是另一种方法,我们知道 Python 讨厌这样做。
Maybe a better question would be to ask why do these operators exist in C. K&R calls increment and decrement operators 'unusual' (Section 2.8page 46). The Introduction calls them 'more concise and often more efficient'. I suspect that the fact that these operations always come up in pointer manipulation also has played a part in their introduction.
In Python it has been probably decided that it made no sense to try to optimise increments (in fact I just did a test in C, and it seems that the gcc-generated assembly uses addl instead of incl in both cases) and there is no pointer arithmetic; so it would have been just One More Way to Do It and we know Python loathes that.
这可能是因为 @GlennMaynard 正在与其他语言进行比较来看待这个问题,但在 Python 中,你可以做 python 的事情方式。这不是一个“为什么”的问题。它就在那里,您可以使用
x+=
执行相同的操作。在The Zen of Python中给出:“应该只有解决问题的一种方法。”多种选择对于艺术(言论自由)来说很棒,但对于工程来说却很糟糕。This may be because @GlennMaynard is looking at the matter as in comparison with other languages, but in Python, you do things the python way. It's not a 'why' question. It's there and you can do things to the same effect with
x+=
. In The Zen of Python, it is given: "there should only be one way to solve a problem." Multiple choices are great in art (freedom of expression) but lousy in engineering.我认为这与对象的可变性和不可变性的概念有关。 2,3,4,5 在 python 中是不可变的。请参阅下图。 2 已经固定了 id 直到这个 python 进程。
x++ 本质上意味着像 C 一样的就地增量。在 C 中,x++ 执行就地增量。因此,x=3,x++ 会将内存中的 3 增加到 4,这与 python 不同,3 仍然存在于内存中。
因此,在 python 中,您不需要在内存中重新创建值。这可能会导致性能优化。
这是基于直觉的答案。
I think this relates to the concepts of mutability and immutability of objects. 2,3,4,5 are immutable in python. Refer to the image below. 2 has fixed id until this python process.
x++ would essentially mean an in-place increment like C. In C, x++ performs in-place increments. So, x=3, and x++ would increment 3 in the memory to 4, unlike python where 3 would still exist in memory.
Thus in python, you don't need to recreate a value in memory. This may lead to performance optimizations.
This is a hunch based answer.
我知道这是一个旧线程,但没有涵盖 ++i 最常见的用例,即在没有提供索引时手动索引集。这种情况就是为什么 python 提供 enumerate()
示例:在任何给定语言中,当您使用像 foreach 这样的构造来迭代集合时 - 为了示例,我们甚至会说它是一个无序集合,并且您需要一个唯一索引对于区分它们的一切,比如
在这种情况下,python 提供了一个枚举方法,例如
I know this is an old thread, but the most common use case for ++i is not covered, that being manually indexing sets when there are no provided indices. This situation is why python provides enumerate()
Example : In any given language, when you use a construct like foreach to iterate over a set - for the sake of the example we'll even say it's an unordered set and you need a unique index for everything to tell them apart, say
In cases like this, python provides an enumerate method, e.g.
除了这里的其他优秀答案之外,
++
和--
也因未定义的行为而臭名昭著。例如,这段代码中发生了什么?它看起来很无辜,但它是错误的 C(和 C++),因为你不知道第一个
bar
是否会增加。一个编译器可能会以一种方式执行,另一个编译器可能会以另一种方式执行,第三种编译器可能会让恶魔从你的鼻子里飞出来。一切都将完全符合 C 和 C++ 标准。(编辑:C++17 已更改给定代码的行为,以便对其进行定义;它将等效于
foo[bar+1] = bar; ++bar;
— 尽管如此,这可能不是程序员所期望的。)未定义的行为在 C 和 C++ 中被视为不可避免的罪恶,但在 Python 中,它只是罪恶,并且要尽可能避免。
In addition to the other excellent answers here,
++
and--
are also notorious for undefined behavior. For example, what happens in this code?It's so innocent-looking, but it's wrong C (and C++), because you don't know whether the first
bar
will have been incremented or not. One compiler might do it one way, another might do it another way, and a third might make demons fly out of your nose. All would be perfectly conformant with the C and C++ standards.(EDIT: C++17 has changed the behavior of the given code so that it is defined; it will be equivalent to
foo[bar+1] = bar; ++bar;
— which nonetheless might not be what the programmer is expecting.)Undefined behavior is seen as a necessary evil in C and C++, but in Python, it's just evil, and avoided as much as possible.