我注意到一个预增量/减量运算符可以应用于变量(如++count
).它编译,但它实际上并没有改变变量的值!
Python中预增量/减量运算符(++/ - )的行为是什么?
为什么Python偏离了C/C++中这些运算符的行为?
++
不是运营商.这是两个+
运营商.该+
运营商的身份运营,这什么都不做.(澄清:+
和-
一元运算符只能处理数字,但我认为你不会指望一个假设的++
运算符来处理字符串.)
++count
解析为
+(+count)
这转化为
count
您必须使用稍长的+=
运算符来执行您想要执行的操作:
count += 1
我怀疑++
和--
操作员是因为一致性和简单性而被排除在外.我不知道Guido van Rossum给出的确切论据,但我可以想象一些论点:
更简单的解析.从技术上讲,解析++count
是模糊的,因为它可能是+
,+
,count
(两个一元+
经营者)一样容易,因为它可能是++
,count
(一个一元++
运算符).这不是一个重要的句法歧义,但确实存在.
更简单的语言.++
只不过是一个同义词+= 1
.这是一个简化发明,因为C编译器是愚蠢的,不知道如何优化大多数计算机a += 1
的inc
指令.在优化编译器和字节码解释语言的今天,向一种语言添加运算符以允许程序员优化其代码通常是不受欢迎的,特别是在像Python这样设计为一致且可读的语言中.
令人困惑的副作用.使用++
运算符的语言中的一个常见新手错误是混合了增量前/减值运算符之间的差异(优先级和返回值),Python喜欢消除语言"gotcha"-s.该优先问题的前/后加用C是相当毛,和令人难以置信的容易陷入困境.
当您想要递增或递减时,通常希望对整数执行此操作.像这样:
b++
但在Python中,整数是不可变的.那是你无法改变它们.这是因为整数对象可以在多个名称下使用.试试这个:
>>> b = 5 >>> a = 5 >>> id(a) 162334512 >>> id(b) 162334512 >>> a is b True
上面的a和b实际上是同一个对象.如果你增加a,你也会增加b.那不是你想要的.所以你必须重新分配.像这样:
b = b + 1
或者更简单:
b += 1
哪个会重新分配b
给b+1
.这不是增量运算符,因为它不会递增b
,而是重新分配它.
简而言之:Python在这里表现不同,因为它不是C,并且不是机器代码的低级包装器,而是高级动态语言,其中增量没有意义,也不像C中那样必要例如,每次有循环时都使用它们.
虽然其他答案是正确的,只要它们表明+
通常只是做什么(即,保留数字,如果它是一个),它们是不完整的,因为它们不解释会发生什么.
确切的说,+x
计算结果为x.__pos__()
和++x
到x.__pos__().__pos__()
.
我可以想象一个非常奇怪的类结构(儿童,不要在家里这样做!)像这样:
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没有这些运算符,但如果你真的需要它们,你可以编写一个具有相同功能的函数.
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
用法:
x = 1 y = PreIncrement('x') #y and x are both 2 a = 1 b = PostIncrement('a') #b is 1 and a is 2
在函数内部,如果要更改局部变量,则必须添加locals()作为第二个参数,否则它将尝试更改全局变量.
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()
您还可以使用以下功能:
x = 1 print(PreIncrement('x')) #print(x+=1) is illegal!
但在我看来,以下方法更加清晰:
x = 1 x+=1 print(x)
减少运营商:
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.
在Python中,与Common Lisp,Scheme或Ruby等语言相比,严格执行表达式和语句之间的区别.
维基百科
因此,通过引入这样的运算符,您将打破表达式/语句拆分.
出于同样的原因你不能写
if x = 0: y = 1
正如你可以在其他语言中那样,不保留这种区别.
是的,我也错过了++和-功能。几百万行c代码使这种思想深深地扎根在我的脑海中,而不是与之抗争……这是我拼凑而成的一类,实现了:
pre- and post-increment, pre- and post-decrement, addition, subtraction, multiplication, division, results assignable as integer, printable, settable.
这是:
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
您可以这样使用它:
c = counter() # defaults to zero for listItem in myList: # imaginary task doSomething(c.postinc(),listItem) # passes c, but becomes c+1
...已经有了c,您可以执行此操作...
c.set(11) while c.predec() > 0: print c
....要不就...
d = counter(11) while d.predec() > 0: print d
...并用于(重新)分配为整数...
c = counter(100) d = c + 223 # assignment as integer c = c + 223 # re-assignment as integer print type(c),c #323
...这将使c保持为类型计数器:
c = counter(100) c.set(c + 223) print type(c),c #323
编辑:
然后还有一些意想不到的(并且完全是不想要的)行为,
c = counter(42) s = '%s: %d' % ('Expecting 42',c) # but getting non-numeric exception print s
...因为在该元组中,没有使用getitem(),而是将对对象的引用传递给格式函数。叹。所以:
c = counter(42) s = '%s: %d' % ('Expecting 42',c.v) # and getting 42. print s
…或更确切地说,是我们实际上想要发生的事情,尽管冗长程度以实际形式c.v
相反(使用代替)……
c = counter(42) s = '%s: %d' % ('Expecting 42',c.__getitem__()) # and getting 42. print s