Behaviour of increment and decrement operators in Python
我注意到可以对变量(如
在python中,pre increment/decrement操作符(++/--)的行为是什么?
为什么Python偏离了C/C++中的这些操作符的行为?
1 | ++count |
解析为
1 | +(+count) |
也就是说
1 | count |
您必须使用稍微长一点的
1 | count += 1 |
我怀疑
- 更简单的解析。从技术上讲,解析
++count 是不明确的,因为它可以是+ 、+ 、count (两个一元+ 操作符),就像解析++ 、count 操作符一样容易。这不是一个明显的句法歧义,但它确实存在。 - 更简单的语言。
++ 只是+= 1 的同义词。这是一个速记发明,因为C编译器很蠢,不知道如何将a += 1 优化成大多数计算机都有的inc 指令。在优化编译器和字节码解释语言的今天,向一种语言添加运算符以允许程序员优化其代码通常是不受欢迎的,特别是在像Python这样设计为一致和可读的语言中。 - 令人困惑的副作用。在使用
++ 运算符的语言中,一个常见的新手错误是混淆了前/后递增/递减运算符之间的差异(优先级和返回值),而python喜欢消除语言"gotcha"—s。C中的前/后递增的优先级问题相当复杂,而且非常容易混淆。
当您想要递增或递减时,通常需要对整数进行递增或递减。像这样:
1 | b++ |
但是在Python中,整数是不可变的。那就是你不能改变它们。这是因为整数对象可以在多个名称下使用。试试这个:
1 2 3 4 5 6 7 8 | >>> b = 5 >>> a = 5 >>> id(a) 162334512 >>> id(b) 162334512 >>> a is b True |
上面的A和B实际上是同一个物体。如果你增加a,你也会增加b,这不是你想要的。所以你必须重新分配。这样地:
1 | b = b + 1 |
或更简单:
1 | b += 1 |
它将把
简而言之:python在这里的行为是不同的,因为它不是C,也不是围绕机器代码的低级包装器,而是一种高级动态语言,在这种语言中,增量没有意义,而且也不像在C中那样必要,例如,在C中,每次有循环时都使用它们。
虽然其他答案是正确的,因为它们表明了一个简单的
准确地说,
我可以想象一个非常奇怪的班级结构(孩子们,不要在家里这样做!)这样地:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class ValueKeeper(object): def __init__(self, value): self.value = value def __str__(self): return str(self.value) class A(ValueKeeper): def __pos__(self): print 'called A.__pos__' return B(self.value - 3) class B(ValueKeeper): def __pos__(self): print 'called B.__pos__' return A(self.value + 19) x = A(430) print x, type(x) print +x, type(+x) print ++x, type(++x) print +++x, type(+++x) |
python没有这些操作符,但是如果您真的需要它们,您可以编写一个具有相同功能的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def PreIncrement(name, local={}): #Equivalent to ++name if name in local: local[name]+=1 return local[name] globals()[name]+=1 return globals()[name] def PostIncrement(name, local={}): #Equivalent to name++ if name in local: local[name]+=1 return local[name]-1 globals()[name]+=1 return globals()[name]-1 |
用途:
1 2 3 4 | x = 1 y = PreIncrement('x') #y and x are both 2 a = 1 b = PostIncrement('a') #b is 1 and a is 2 |
如果要更改局部变量,必须在函数内部添加locals()作为第二个参数,否则它将尝试更改全局变量。
1 2 3 4 5 6 | x = 1 def test(): x = 10 y = PreIncrement('x') #y will be 2, local x will be still 10 and global x will be changed to 2 z = PreIncrement('x', locals()) #z will be 11, local x will be 11 and global x will be unaltered test() |
还可以使用这些功能:
1 2 | x = 1 print(PreIncrement('x')) #print(x+=1) is illegal! |
但在我看来,以下方法更为明确:
1 2 3 | x = 1 x+=1 print(x) |
减量运算符:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def PreDecrement(name, local={}): #Equivalent to --name if name in local: local[name]-=1 return local[name] globals()[name]-=1 return globals()[name] def PostDecrement(name, local={}): #Equivalent to name-- if name in local: local[name]-=1 return local[name]+1 globals()[name]-=1 return globals()[name]+1 |
我在模块中将javascript转换为python时使用了这些函数。
In Python, a distinction between expressions and statements is rigidly
enforced, in contrast to languages such as Common Lisp, Scheme, or
Ruby.
维基百科
因此,通过引入这样的运算符,您将破坏表达式/语句的拆分。
因为同样的原因你不能写
1 2 | if x = 0: y = 1 |
在某些其他语言中,这种区别是无法保留的。
是的,我也错过了++和--功能。几百万行C代码把这种思想灌输到我的老脑袋里,而不是与之抗争……下面是我整理的一个类,它实现了:
1 2 3 | pre- and post-increment, pre- and post-decrement, addition, subtraction, multiplication, division, results assignable as integer, printable, settable. |
这里是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | class counter(object): def __init__(self,v=0): self.set(v) def preinc(self): self.v += 1 return self.v def predec(self): self.v -= 1 return self.v def postinc(self): self.v += 1 return self.v - 1 def postdec(self): self.v -= 1 return self.v + 1 def __add__(self,addend): return self.v + addend def __sub__(self,subtrahend): return self.v - subtrahend def __mul__(self,multiplier): return self.v * multiplier def __div__(self,divisor): return self.v / divisor def __getitem__(self): return self.v def __str__(self): return str(self.v) def set(self,v): if type(v) != int: v = 0 self.v = v |
您可以这样使用它:
1 2 3 | c = counter() # defaults to zero for listItem in myList: # imaginary task doSomething(c.postinc(),listItem) # passes c, but becomes c+1 |
…已经有了C,你可以这样做…
1 2 3 | c.set(11) while c.predec() > 0: print c |
…或者只是…
1 2 3 | d = counter(11) while d.predec() > 0: print d |
…并将(重新)赋值为整数…
1 2 3 4 | c = counter(100) d = c + 223 # assignment as integer c = c + 223 # re-assignment as integer print type(c),c # <type 'int'> 323 |
…而这将保持C作为类型计数器:
1 2 3 | c = counter(100) c.set(c + 223) print type(c),c # <class '__main__.counter'> 323 |
编辑:
还有一些意想不到的(完全不需要的)行为,
1 2 3 | c = counter(42) s = '%s: %d' % ('Expecting 42',c) # but getting non-numeric exception print s |
…因为在该元组中,getItem()不是所使用的,而是将对对象的引用传递给格式化函数。叹息。所以:
1 2 3 | c = counter(42) s = '%s: %d' % ('Expecting 42',c.v) # and getting 42. print s |
…或者,更确切地说,更明确地说,我们实际想要发生的事情,尽管详细程度以实际形式表示(使用
1 2 3 | c = counter(42) s = '%s: %d' % ('Expecting 42',c.__getitem__()) # and getting 42. print s |
DR
python没有一元递增/递减运算符(
1 | a += 1 |
更多细节和细节
但这里要小心。如果您来自C,即使这在Python中也是不同的。在C的意义上,python没有"变量",相反,python使用名称和对象,在python中,
所以说你会的
1 | a = 1 |
在python中,这意味着:创建一个值为
现在我们假设你做了
1 | a += 1 |
由于
你自己试试吧:
1 2 3 4 | a = 1 print(hex(id(a))) a += 1 print(hex(id(a))) |