为什么python中没有++和--操作符?
- python中递增和递减运算符的相关post行为
- 因为…Python不是C!
这并不是因为它没有意义;把"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引擎);支持逻辑增量的每个类都需要实现它们(在+=和-=。
这与+=和-=都是多余的,因此它将成为净损失。
- 使用数组[I++]通常很有用,它不是用+=/-=整齐地完成的。
- @Thayes:这不是Python中常见的模式。
- @是的,因为这将在一个循环内,所以您也可以直接循环i--如果您确实需要它,并且不能只使用array.append()。
- 我看到更大的问题是可读性和可预测性。在我的C时代,我看到了足够多的错误源于对i++和++i之间区别的误解…
- 我相信在"C"世界里,它是最有效地使用(不是最常用的)指针的。有一个直接映射到一些支持地址寄存器预增量或后增量的指令集-M68K作为这一点的早期支持者出现在我们的脑海中。因为Python中没有指针,所以它是多余的。
- 在事实上加上一个理由:在我研究的一个项目中,我遇到了(比任何人都应该在他们的生活中)大量的C++代码,这些问题被EDOCX1 6和EDCX1 7所困扰。它们使得编写复杂的、难以正确解析代码成为可能。
- 像EDOCX1[0]这样的分解确实很难看。您不能直接替换为i+=1或i=i+1,必须更改多行代码。
- @我不确定你是否理解答案。重点是,与C语言不同,在Python中不需要经常增加一个。如果你发现你一直在这样做,你可能还没有完全使用语言(for、xrange、enumerate等)。
- 格伦,我不确定你是否理解我的评论。如果您使用的是xrange、enumerate、for等,当您事先不知道要处理的项目数时,可能无法正确编程。
- 对不起,这没有道理。您不需要PostIncrement来写"for item in some_list",或者在大多数其他情况下,您通常需要它在C中。
- 我认为,与array[i]++相比,array[i++]更容易丢失——前者可能在循环的其他地方完成,但后者需要创建一个一次性的临时变量和至少两行额外的代码。
- @编码员array[i] += 1也会这样做,不是吗?
- 他们没有理由需要额外的操作码。
- @glennmaynard在迭代器return self.vertices[self.current++]中是不错的。
我写的这个原始答案是来自计算机的民间传说的一个神话:丹尼斯·里奇揭穿了"历史上不可能"的事实,正如给ACM通讯编辑的信2012年7月doi:10.1145/2209249.2209251所述。
C递增/递减运算符是在C编译器不是很聪明的时候发明的,作者希望能够指定应该使用机器语言运算符的直接意图,这样可以为编译器节省一些周期,而编译器可以执行
1 2 3 4
| load memory
load 1
add
store memory |
而不是
PDP-11甚至分别支持对应于*++p和*p++的"autoincrement"和"autoincrement deferred"指令。如果非常好奇,请参见手册第5.3节。
由于编译器足够聪明,能够处理C语法中内置的高级优化技巧,所以它们现在只是一种语法上的便利。
Python没有向汇编程序传递意图的技巧,因为它不使用意图。
- javascript有++。我不认为这是"向汇编程序传达意图的技巧",另外,Python确实有字节码。所以我认为原因是别的。
- 这种"向编译器提供提示"的业务实际上是一个神话。坦率地说,这是对任何语言的一个愚蠢的补充,它违反了以下两条戒律:1。你不编码让电脑阅读,你编码让另一个工程师阅读。2。你不需要编码让一个称职的工程师去阅读,你需要编码让一个称职的工程师在凌晨3点精疲力竭的时候去阅读,然后跳上咖啡因。
- @TGM1024公平地说,当以每秒10-30个字符的半双工电传打字机进行编码时,需要进行编码,以便在下周之前输入。
- @MSW,恐怕我错过了你的意思。
- @TGM1024 Unix和C最初的大部分开发都是在PDP-11S上进行的,在用户通信中使用了非常慢的电传打字机。虽然你说得很对,但是今天对机器的编码基本上是愚蠢的,那时候的瓶颈是人机界面。如果你不必这么做,很难想象工作会如此缓慢。
我一直认为这与Python禅的这一行有关:
There should be one — and preferably only one — obvious way to do it.
X++和X+=1做了完全相同的事情,所以没有理由两者都有。
- 好,那我们删除+=运算符?
- one--是零?
- one--是句子中的一个,但之后立即为零。所以这个"koan"也暗示了递增/递减操作符是不明显的。
- em破折号通常用ASCII作为两个连字符书写,但@Victork的解释更有趣。
- @gsto:如果x++和x+=1做了同样的事情,你能告诉我(x++)和(x+=1)的值吗?我认为后者在python中没有任何价值——相反,请求它会导致语法错误。我想在内联for循环中保留类型子集的计数。X++可以很好地完成这个技巧。
- @ EralpB但+= 2
- @如果删除+=,则不能执行X+=10之类的操作。+=是更一般的情况++
- 还有:"显性优于隐性"。
- @维克多:事实上,"一——"是句子中的一个,但之后减去一个。因为它会发生两次。更不明显的是:)尽管,第二个可能是预先定义的"明显"…
- 当然不一样,因为x+=1不是一个表达式——它是一个语句——它不计算任何值。你不能这样做:"row[col++]=a;row[col++]=b"。更不用说C++的前Inc和PixInc的东西了。
- 这些不一样…如果a++==3,如何使用+=?
- @CPBL,请澄清。我知道我们谈论的是python,但是a=x++;a=(x++);当然,在c中产生的结果完全相同。
- @TGM1024,哇…(很久以前,现在…)我的意思就是乌里上面说的。
- 关于x+=1不是表达式?也许是Python。但是在C和C++中,我相信所有的作业,甚至是奇怪的复合作业都是表达式。这就是为什么a=b=c;首先在这些语言中工作(以及从右到左的分组)。
- x++和x+=1不是一回事。
- @Rory如果你删除+=那么你仍然可以做X+=10之类的事情。你可以做x=x+10。
- 根据这种逻辑,+=也不应该存在,因为您可以只使用x = x + n。但是+=更方便。同样,++是添加1的更方便的方法。
当然,我们可以说"吉多就是这样决定的",但我认为这个问题实际上是关于这个决定的原因。我认为有几个原因:
- 它将语句和表达式混合在一起,这不是很好的实践。请参阅http://norvig.com/python-iaq.html
- 它通常鼓励人们编写可读性较低的代码
- 正如前面提到的,语言实现中的额外复杂性在Python中是不必要的。
- 很高兴有人最后提到了陈述与表达的关系。在C中,赋值是一个表达式,因此它是一个+运算符。在python中,赋值是一个语句,所以如果它有一个++,它可能也需要一个赋值语句(甚至不太有用或不需要)。
- 同意-如果他们是声明,那么至少,谈论后操作员和前操作员之间的区别是毫无意义的。
因为,在python中,整数是不可变的(int的+=实际上返回一个不同的对象)。
另外,使用++/--时,您需要担心前后的增量/减量,并且只需再按一次键即可写入x+=1。换言之,它避免了潜在的混乱,而牺牲了很少的收益。
- 整数在C中也是不变的。如果您不这么认为,请尝试让C编译器为42++生成代码…在一些旧的Fortran编译器中(我已经读到了),类似这样的事情(修改一个文字常量)实际上是可能的:在该程序运行中,该文字的所有未来使用都将具有不同的值。调试愉快!
- 正确的。42是字面常量。常量是(或至少应该是)不可变的。这并不意味着c-int一般是不变的。c中的int只指定内存中的一个位置。在那个地方的比特是非常易变的。例如,您可以创建int的引用并更改该引用的引用。在该位置的所有引用(包括原始int变量)中都可以看到此更改。对于python integer对象,这一点并不适用。
- x+=1不会最终成为inc mem。python执行一个函数调用向变量添加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才被添加。
- 是的,伙计,你可以用return a[i=i+1]代替return a[i++]。
我对为什么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现在指向另一个对象作为变量b和c。因为你已经使用了a = a + 1,所以很明显。换言之,您完全将另一个对象分配给标签a。假设您可以编写a++,它将建议您不要将变量a分配给新对象,而是将旧对象的增量增加。所有这些都是为了最小化混乱。为了更好地理解python变量的工作原理:
在Python中,为什么函数可以修改调用方所感知的某些参数,而不能修改其他参数?
python是按值调用还是按引用调用?两者都不。
python是按值传递还是按引用传递?
python是按引用传递还是按值传递?
python:如何通过引用传递变量?
了解python变量和内存管理
在python中模拟传递值行为
通过引用调用python函数
像Python一样的代码:惯用的Python
我对python非常陌生,但我怀疑原因是因为它强调语言中可变和不可变的对象。现在,我知道x++可以很容易地解释为x=x+1,但看起来您正在增加一个可能是不可变的对象。
只是我的猜测/感觉/预感。
- 在这方面,x++比x = x + 1更接近x += 1,这两者在易变物体上也有区别。
首先,python只是间接地受c的影响;它深受abc的影响,abc显然没有这些操作符,所以在python中也找不到它们也不奇怪。
其次,正如其他人所说,增加和减少已经得到了+=和-=的支持。
第三,对++和--操作符集的完全支持通常包括对它们的前缀和后缀版本的支持。在C和C++中,这可能会导致各种"可爱"的结构,似乎对我来说,与Python拥抱的简单和直率的精神背道而驰。
例如,对于一个有经验的程序员来说,C语句while(*t++ = *s++);可能看起来简单而优雅,而对于学习它的人来说,它就不简单了。加上前缀和后缀的增量和减量,甚至许多专业人士也不得不停下来想一想。
我相信这源于python的信条"显式优于隐式"。
- 好吧,您没有在Python中显式地编写"begin"和"end"语句,对吧?尽管我同意这一说法,但我认为这是有界限的。虽然我们可以在这一界限上争论,但我认为我们都可以同意,有一条线是不现实的。既然对这个决定有这么多的意见和理由,我认为这不是一个明确的选择。至少,我找不到一个明确说明的来源
这可能是因为@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。
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循环等中使用++运算符,但不能使用+=。在底部,我们感觉到了需要++和——,因为这个原因。
- 这是错误的,至少对于C/C++来说是错误的。您可以在for循环、if语句等中使用+=。它是一个类似赋值的表达式,返回加法的结果。