python为什么没有++和 – – 运算符

Why are there no ++ and --? operators in Python?

为什么python中没有++--操作符?


这并不是因为它没有意义;把"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引擎);支持逻辑增量的每个类都需要实现它们(在+=-=

这与+=-=都是多余的,因此它将成为净损失。


我写的这个原始答案是来自计算机的民间传说的一个神话:丹尼斯·里奇揭穿了"历史上不可能"的事实,正如给ACM通讯编辑的信2012年7月doi:10.1145/2209249.2209251所述。


C递增/递减运算符是在C编译器不是很聪明的时候发明的,作者希望能够指定应该使用机器语言运算符的直接意图,这样可以为编译器节省一些周期,而编译器可以执行

1
2
3
4
load memory
load 1
add
store memory

而不是

1
inc memory

PDP-11甚至分别支持对应于*++p*p++的"autoincrement"和"autoincrement deferred"指令。如果非常好奇,请参见手册第5.3节。

由于编译器足够聪明,能够处理C语法中内置的高级优化技巧,所以它们现在只是一种语法上的便利。

Python没有向汇编程序传递意图的技巧,因为它不使用意图。


我一直认为这与Python禅的这一行有关:

There should be one — and preferably only one — obvious way to do it.

X++和X+=1做了完全相同的事情,所以没有理由两者都有。


当然,我们可以说"吉多就是这样决定的",但我认为这个问题实际上是关于这个决定的原因。我认为有几个原因:

  • 它将语句和表达式混合在一起,这不是很好的实践。请参阅http://norvig.com/python-iaq.html
  • 它通常鼓励人们编写可读性较低的代码
  • 正如前面提到的,语言实现中的额外复杂性在Python中是不必要的。


因为,在python中,整数是不可变的(int的+=实际上返回一个不同的对象)。

另外,使用++/--时,您需要担心前后的增量/减量,并且只需再按一次键即可写入x+=1。换言之,它避免了潜在的混乱,而牺牲了很少的收益。


清晰!

python非常清晰,没有一个程序员能够正确猜测--a的含义,除非他/她学习了一种具有这种结构的语言。

python也非常注重避免导致错误的构造,并且++操作符被认为是缺陷的丰富来源。这两个原因不足以在Python中使用这些运算符。

python使用缩进来标记块的决定比一些句法手段,如某种形式的开始/结束括号或者强制性的末端标记在很大程度上基于相同的考虑。

为了举例说明,请看一下关于在2005年将条件运算符(在C:cond ? resultif : resultelse中)引入Python的讨论。至少阅读该讨论的第一条消息和决定消息(之前在同一主题上有几个前兆)。

琐事:其中经常提到的PEP是"python扩展建议"PEP 308。lc表示列表理解,ge表示生成器表达式(不用担心,如果它们混淆了您,它们不是Python中少数几个复杂的地方)。


它就是这样设计的。递增和递减运算符只是x = x + 1的快捷方式。Python通常采用一种设计策略,它减少了执行操作的可选方法的数量。在python中,增广赋值是最接近增量/减量运算符的东西,它们甚至直到python 2.0才被添加。


我对为什么python没有++操作符的理解如下:当您在python a=b=c=1中编写它时,您将得到三个变量(标签)指向同一对象(值为1)。您可以使用ID函数来验证这一点,该函数将返回一个对象内存地址:

1
2
3
4
5
6
7
8
In [19]: id(a)
Out[19]: 34019256

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

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

所有三个变量(标签)都指向同一个对象。现在增加一个变量,看看它如何影响内存地址:

1
2
3
4
5
6
7
8
9
10
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

您可以看到变量a现在指向另一个对象作为变量bc。因为你已经使用了a = a + 1,所以很明显。换言之,您完全将另一个对象分配给标签a。假设您可以编写a++,它将建议您不要将变量a分配给新对象,而是将旧对象的增量增加。所有这些都是为了最小化混乱。为了更好地理解python变量的工作原理:

在Python中,为什么函数可以修改调用方所感知的某些参数,而不能修改其他参数?

python是按值调用还是按引用调用?两者都不。

python是按值传递还是按引用传递?

python是按引用传递还是按值传递?

python:如何通过引用传递变量?

了解python变量和内存管理

在python中模拟传递值行为

通过引用调用python函数

像Python一样的代码:惯用的Python


我对python非常陌生,但我怀疑原因是因为它强调语言中可变和不可变的对象。现在,我知道x++可以很容易地解释为x=x+1,但看起来您正在增加一个可能是不可变的对象。

只是我的猜测/感觉/预感。


首先,python只是间接地受c的影响;它深受abc的影响,abc显然没有这些操作符,所以在python中也找不到它们也不奇怪。

其次,正如其他人所说,增加和减少已经得到了+=-=的支持。

第三,对++--操作符集的完全支持通常包括对它们的前缀和后缀版本的支持。在C和C++中,这可能会导致各种"可爱"的结构,似乎对我来说,与Python拥抱的简单和直率的精神背道而驰。

例如,对于一个有经验的程序员来说,C语句while(*t++ = *s++);可能看起来简单而优雅,而对于学习它的人来说,它就不简单了。加上前缀和后缀的增量和减量,甚至许多专业人士也不得不停下来想一想。


我相信这源于python的信条"显式优于隐式"。


这可能是因为@glennmaynard将这一问题与其他语言进行了比较,但在Python中,您以Python的方式进行操作。这不是"为什么"的问题。它就在那里,你可以用x+=做同样的事情。在《Python禅》中,有一句话是这样说的:"只有一种方法可以解决一个问题。"多重选择在艺术上是伟大的(表达自由),但在工程上却是糟糕的。


正如我所理解的那样,你不会认为内存中的值发生了变化。在C语言中,当您执行X++时,内存中X的值会发生变化。但在python中,所有数字都是不可变的,因此x指向的地址仍然有x而不是x+1。当你写x++的时候,你会认为x改变了,真正发生的是x引用被改变到内存中存储x+1的位置,或者如果doe不存在,重新创建这个位置。


++类运算符是带有副作用的表达式。这通常是在Python中找不到的。

出于同样的原因,赋值不是Python中的表达式,因此无法使用常见的if (a = f(...)) { /* using a here */ }习惯用法。

最后,我怀疑这里的运算符与pythons引用语义不太一致。请记住,Python没有从C/C++中已知的语义变量(或指针)。


也许一个更好的问题应该是问,为什么在C.K&R调用中存在这些运算符?递增和递减运算符"异常"(第46页第2.8节)。引言中称之为"更简洁、更高效"。我怀疑这些操作总是出现在指针操作中,这一事实在它们的介绍中也起到了一定的作用。在python中,可能已经决定尝试优化增量是没有意义的(事实上,我刚刚用C做了一个测试,gcc生成的程序集似乎使用addl而不是在这两种情况下都包含),并且没有指针算法;因此,这只是一种方法,我们知道python不喜欢这样做。


我认为这与物体的可变性和不可变性的概念有关。2、3、4、5在python中是不可变的。请参阅下图。在这个python进程之前,2具有固定的ID。

ID of constants and variables

x++基本上意味着一个就地增量,就像c一样。在c中,x++执行就地增量。因此,x=3,x++会将内存中的3增加到4,而不像python那样,3仍然存在于内存中。

因此,在Python中,不需要在内存中重新创建值。这可能导致性能优化。

这是一个基于直觉的答案。


要在该页上完成已经很好的答案:

假设我们决定这样做,前缀(++i将破坏一元+和-运算符。

今天,++--的前缀没有任何作用,因为它启用一元加运算符两次(什么也不做)或一元减两次(两次:取消本身)。

1
2
3
4
5
>>> i=12
>>> ++i
12
>>> --i
12

所以这可能会打破这种逻辑。


++运算符与+=运算符不完全相同。事实上,两者的结果是相同的,但使用有一些不同。例如,可以在三元条件、for循环等中使用++运算符,但不能使用+=。在底部,我们感觉到了需要++和——,因为这个原因。