为什么Python中没有++和 - 运算符?

Leo*_*nid 426 python operators

为什么没有++--Python中的运营商?

Gle*_*ard 432

这不是因为它没有意义; 将"x ++"定义为"x + = 1,评估x的先前绑定"是完全合理的.

如果你想知道最初的原因,你必须要么通过旧的Python邮件列表或者询问那里的人(例如Guido),但事实证明这很容易证明:

不需要像其他语言那样简单的增量和减量.你不for(int i = 0; i < 10; ++i)经常写Python之类的东西; 相反,你做的事情for i in range(0, 10).

由于它几乎不需要经常使用,因此没有理由给它自己特殊的语法; 当你需要增加时,+=通常就好了.

这不是决定它是否有意义,或者它是否可以完成 - 它确实如此,它可以.这是一个问题,是否有益于增加语言的核心语法.请记住,这是四个运算符 - postinc,postdec,preinc,predec,并且每个运算符都需要有自己的类重载; 他们都需要被指定和测试; 它会在语言中添加操作码(暗示一个更大的,因此更慢的VM引擎); 每个支持逻辑增量的类都需要实现它们(在+=和之上-=).

这对于+=-=,都是多余的,因此它将成为净损失.

  • 使用像array [i ++]这样的东西通常很有用,而这些东西并不是用+ =/ - =来完成的. (95认同)
  • @thayes:这不是Python中常见的模式. (95认同)
  • 我看到更大的问题是可读性和可预测性.回到我的C日,我看到了很多关于"i ++"和"++ i"之间区别的误解的错误...... (30认同)
  • @thayes因为那将是一个循环,你也可以直接循环`i` - 如果你真的需要它而不能只是例如使用`array.append()` (9认同)
  • 事后补充说明:在我工作的项目上,我遇到过(比他们生命中任何人都应该多)相当多的C++代码,这些代码遇到了`++`和` - `的问题以导致未定义或未指定行为的方式.它们使编写复杂,难以正确解析的代码成为可能. (5认同)
  • @LuísdeSousa我不确定你是否理解答案。关键是,与C语言不同,您不需要在Python中经常一次递增。如果发现自己一直在使用它,则可能尚未完全使用该语言(例如,xrange,枚举等)。 (2认同)
  • 抱歉,这没有意义。您不需要后增量来编写“for item in some_list”,或者在大多数其他情况下,您通常需要在 C 中使用它。 (2认同)

msw*_*msw 82

我写的这个原始答案是来自计算民间传说的神话:Dennis Ritchie将其揭穿为"历史上不可能",如2012年7月ACM通讯编辑的信中所述:10.1145/2209249.2209251


C增量/减量运算符是在C编译器不是很聪明的时候发明的,并且作者希望能够指定应该使用机器语言运算符的直接意图,这为编译器保存了一些循环.可能会做一个

load memory
load 1
add
store memory
Run Code Online (Sandbox Code Playgroud)

代替

inc memory 
Run Code Online (Sandbox Code Playgroud)

并且PDP-11甚至支持分别对应于*++p和的"自动增量"和"自动递增延迟"指令*p++.如果非常好奇,请参阅手册的第5.3节.

由于编译器足够聪明,可以处理C语法中内置的高级优化技巧,因此它们现在只是语法上的便利.

Python没有把意图传达给汇编程序的技巧,因为它没有使用它.

  • 这"向编译器提供提示"业务确实是一个神话.坦率地说,这是对任何语言的愚蠢补充,它违反了以下两条规则:**1.您没有为计算机编写代码,您为其他工程师编写代码进行编码.**和**2.您没有为有能力的工程师编写代码,您需要为有能力的工程师编写代码,以便在凌晨3点用尽时阅读,然后加入咖啡因.** (11认同)
  • Javascript有++.我不认为这是"向汇编者传达意图的伎俩".另外,Python确实有字节码.所以我认为原因是别的. (4认同)
  • @ tgm1024 Unix和C在PDP-11上看到了大部分的初始开发,这些开发使用了令人难以置信的慢速电话类型进行用户通信.虽然你已经死了,但今天*机器的编码大多是愚蠢的,那么人类/机器接口就是瓶颈.如果你从来没有这么做,很难想象慢慢地工作. (4认同)
  • @ tgm1024公平地说,当你以每秒10-30个字符编码半双工电传打字时,你需要进行编码,这样你就可以在下周之前将其键入. (3认同)

GSt*_*Sto 63

我总是认为它与python的这一行有关:

应该有一个 - 最好只有一个 - 显而易见的方法.

x ++和x + = 1完全相同,所以没有理由同时使用两者.

  • `one - `在句子中是一个,但之后立即为零.所以这个'koan'也暗示增量/减量运算符是不明显的. (24认同)
  • @EralpB如果删除+ =,则不能执行x + = 10之类的操作.+ =是++的更一般情况 (14认同)
  • `one - `是零? (10认同)
  • 另外:"明确比隐含更好". (8认同)
  • @EralpB但+ = 2 (2认同)
  • 绝对不一样,因为x + = 1不是表达式 - 它是一个声明 - 它不会评估任何东西.你不能做的事情:'row [col ++] = a; row [col ++] = b'.更不用说c ++拥有的pre-inc和post-inc之类的东西了. (2认同)
  • `x ++`和`x + = 1`不是一回事. (2认同)
  • @Rory如果删除+ =那么你可以做x + = 10之类的事情.你可以做x = x + 10. (2认同)
  • 按照这个逻辑,`+=`也不应该存在,因为你可以只使用`x = x + n`。但 `+=` _更方便_。同样,“++”是一种更方便的加 1 的方法。 (2认同)

EMP*_*EMP 36

当然,我们可以说"Guido就是这样决定的",但我认为这个问题的真正原因在于这个决定.我认为有几个原因:

  • 它将语句和表达混合在一起,这不是一个好习惯.请参见http://norvig.com/python-iaq.html
  • 它通常鼓励人们编写不太可读的代码
  • 语言实现的额外复杂性,如前所述,这在Python中是不必要的

  • 很高兴有人最终提到声明vs表达方面.在C赋值中是一个表达式,因此它是++运算符.在Python中,赋值是一个语句,所以__if__它有一个++,它也可能需要一个赋值语句(甚至更少有用或者需要). (10认同)

Nat*_*vis 16

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

此外,使用++/ - 您需要担心前后增量/减量,并且只需要再写一次键击x+=1.换句话说,它以非常小的收益为代价避免了潜在的混淆.

  • 对.42是文字*常数*.常量是(或至少*应该*)不可变的.这并不意味着C`int一般是不可变的.C中的`int`只是在内存中指定一个位置.而那个地方的位是非常可变的.例如,您可以创建`int`的引用并更改该引用的引用.此更改在所有引用(包括原始`int`变量)中可见到该位置.同样不适用于Python整数对象. (10认同)
  • “只需要再敲一次键就可以写出 x+=1”,除了 a[x+=1] 不起作用,这在其他语言中是很常见的模式。如果有更根本的原因导致这行不通,那么糟糕的语言设计似乎被用来防止人们犯错误——Python 真的以这种方式被称为/使用为“安全”语言吗?您给出的解释似乎与 Python 的其他语言设计选择不一致。 (2认同)

Lut*_*elt 12

明晰!

Python非常清晰,没有程序员可能正确地猜测其含义,--a除非他/他学会了具有该结构的语言.

Python也是很多关于避免引发错误的构造,并且++已知运算符是丰富的缺陷源.这两个原因足以让Python中没有这些运算符.

Python使用缩进来标记块而不是语法手段(例如某种形式的开始/结束包围或强制结束标记)的决定主要基于相同的考虑因素.

为了说明,看看在各地引入有条件的经营者讨论(在C: cond ? resultif : resultelse)至少在2005年读成Python的第一条消息决策信息是的讨论(这不会对同一主题的几个前体之前).

琐事: 其中经常提到的PEP是"Python扩展提案" PEP 308.LC意味着列表理解,GE意味着生成器表达(如果那些让你困惑,不要担心,它们不是Python的少数复杂点).

  • 像 f"{1:03}" 这样的行为(用前导零填充字符串)是完全清晰和直观的,但几乎所有编程语言中存在的几十年前的编程模式却并非如此。知道了。 (2认同)

Ree*_*sey 9

它就是这样设计的.递增和递减运算符只是快捷方式x = x + 1.Python通常采用一种设计策略,减少了执行操作的替代方法的数量. 增强赋值是最接近Python中递增/递减运算符的东西,它们甚至在Python 2.0之前都没有添加.

  • 是的伙伴,比如,你可以用`return a [i = i + 1]`替换`return a [i ++]`. (3认同)

Wak*_*nka 8

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

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

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

In [21]: id(c)
Out[21]: 34019256
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

您可以看到该变量a现在指向另一个对象作为变量bc.因为你已经习惯了a = a + 1它是明确的.换句话说,您将另一个对象分配给标签a.想象一下,你可以写a++它会建议你没有分配给变量a新对象但是ratter增加旧对象.所有这些东西都是恕我直言,以尽量减少混乱.为了更好地理解python变量的工作原理:

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

Python是按值调用还是按引用调用?都不是.

Python是通过值传递还是通过引用传递?

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

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

了解Python变量和内存管理

在python中模拟按值传递行为

Python函数通过引用调用

代码像Pythonista:惯用语Python


mko*_*nen 7

我对python很新,但我怀疑原因是因为语言中可变和不可变对象之间的重点.现在,我知道X ++很容易被解释为X = X + 1,但它看起来像你递增就地对象可能是不可改变的.

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


Jea*_*bre 5

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

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

今天,前缀++or--不执行任何操作,因为它启用一元加运算符两次(不执行任何操作)或一元减运算符两次(两次:取消自身)

>>> i=12
>>> ++i
12
>>> --i
12
Run Code Online (Sandbox Code Playgroud)

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

现在,如果需要列表推导或 lambda,从 python 3.8 开始,可以使用新的:=赋值运算符 ( PEP572 )

预递增a并将其分配给b

>>> a = 1
>>> b = (a:=a+1)
>>> b
2
>>> a
2
Run Code Online (Sandbox Code Playgroud)

后递增只需要通过减 1 来弥补过早的加法:

>>> a = 1
>>> b = (a:=a+1)-1
>>> b
1
>>> a
2
Run Code Online (Sandbox Code Playgroud)