我注意到可以将预增减运算符应用于变量(例如++count)。它可以编译,但实际上并没有改变变量的值!

Python中预增/减算符(++ /-)的行为是什么?

为什么Python会偏离在C / C ++中看到的这些运算符的行为?

评论

Python不是C或C ++。语言的设计决策各不相同。特别是,Python故意没有定义可在任意表达式中使用的赋值运算符。而是有赋值语句和扩充的赋值语句。请参阅下面的参考。

是什么让您认为python具有++和-运算符?

Kaizer:来自C / C ++,我编写++ count,它在Python中编译。因此,我认为该语言具有运算符。

@Fox您假设没有明显的计划和组织水平

@mehaase ++和-在c中不存在“作为指针算术的语法糖”,它们之所以存在,是因为许多处理器将自动递增和递减内存访问机制(通常是指针索引,堆栈索引)作为其本机指令的一部分组。例如,在6809汇编程序中:sta x ++ ...产生的原子指令将x指向的累加器存储在其中,然后将x累加到累加器的大小。这样做是因为它比指针算术更快,因为它很常见,并且很容易理解。前和后。

#1 楼

++不是运算符。它是两个+运算符。 +运算符是身份运算符,不执行任何操作。 (澄清:+-一元运算符仅适用于数字,但我想您不会期望假设的++运算符适用于字符串。)

++count


解析为

+(+count)


翻译为

count


您必须使用稍长的+=运算符来执行您想做什么:

count += 1


我怀疑++--运算符出于一致性和简单性而被忽略了。我不知道Guido van Rossum做出决定的确切论据,但我可以想象几个论点:


更简单的解析。从技术上讲,解析++count是模棱两可的,因为它可能像++(一个一元count运算符)一样容易地被解析为+++count(两个一元++运算符)。它不是语法上的明显歧义,但确实存在。
简单的语言。 ++只是+= 1的同义词。因为C编译器很笨,并且不知道如何将a += 1优化为大多数计算机具有的inc指令,所以发明了这种简写。在优化编译器和字节码解释语言的这一天,通常不赞成在一种语言中添加运算符以允许程序员优化其代码,尤其是在像Python这样设计成一致且易读的语言中。
令人困惑的是,效果。使用++运算符的语言中一个常见的新手错误是混淆前后递增/递减运算符之间的差异(优先级和返回值),Python喜欢消除语言“陷阱”。 C中的预增/后增的优先级问题非常棘手,难以置信。


评论


“ +运算符是“身份”运算符,它什么也不做。”仅适用于数字类型;对于其他类型,默认情况下为错误。

– newacct
09年9月28日在7:47

另外,请注意,在Python中,+ =和friends不是可在表达式中使用的运算符。而是在Python中将它们定义为“增强的赋值语句”的一部分。这与Python中的语言设计决策一致,即不允许在任意表达式中将赋值(“ =”)作为运算符,这与C语言中的操作不同。请参阅docs.python.org/reference/…

–内德·迪利(Ned Deily)
09年9月28日在8:06

一元+运算符有用途。对于decimal.Decimal对象,将四舍五入到当前精度。

–u0b34a0f6ae
09年9月28日在9:10

我押注解析器的简化。请注意PEP 3099中的一个项目,“ Python 3000中不会改变的事情”:“解析器不会比LL(1)复杂。简单总比复杂要好。这个想法扩展到了解析器。Python的语法仅限于LL(1)解析器是一种福气,而不是诅咒。它把我们带到手铐上,可以防止我们过度学习并最终得到时髦的语法规则,如一些其他不愿透露名称的动态语言,例如Perl。”我看不出如何在不破坏LL(1)的情况下消除++和++的歧义。

–迈克·德西蒙(Mike DeSimone)
2010-10-14 19:42

说++只不过是+ = 1的同义词是不正确的。++存在++的递增和递减变体,因此显然不是同一回事。不过,我同意您的其他观点。

– PhilHibbs
17年5月17日在8:59

#2 楼

当您想增加或减少时,通常需要对整数进行操作。像这样:

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中那样必要,因为C在每次循环时都使用它们。

评论


这个例子是错误的(您可能会将不变性与身份混淆)-由于某些虚拟机优化,它们使用相同的对象直到255(或类似的数字),因此它们具有相同的ID。例如(更大的数字):>>> a = 1231231231231 >>> b = 1231231231231 >>> id(a),id(b)(32171144,32171168)

–ionelmc
2010年1月11日下午1:00



不变性主张是虚假的。从概念上讲,i ++意味着将i + 1分配给变量i。 i = 5; i ++的意思是给i赋6,而不修改i指向的int对象。也就是说,这并不意味着增加5的值!

–机械蜗牛
2011-09-20 4:19



@机械蜗牛:在这种情况下,它根本不是增量运算符。然后+ =运算符会更清晰,更明确,更灵活,并且仍然可以执行相同的操作。

– Lennart Regebro
2011-09-20 5:35

@LennartRegebro:在C ++和Java中,i ++仅在左值上运行。如果要增加i指向的对象,则此限制是不必要的。

–机械蜗牛
2011-09-20 7:18

我觉得这个答案令人困惑。为什么要假设++意味着+ = 1的简写呢?这正是C语言的含义(假设未使用返回值)。您似乎想出了一些其他含义。

–唐·哈奇
18年7月13日在0:32

#3 楼

尽管其他答案在表明仅+通常会做的事情上是正确的(即,将数字保留为原来的数字,如果是一个数字),但在不解释会发生什么的情况下,它们是不完整的。 br />
确切地说,+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)


#4 楼

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的模块中使用了这些功能。

评论


注意:虽然很棒,但是如果您的本地人存在于类函数堆栈框架中,则这些帮助程序方法将不起作用。即-从类方法def中调用它们将不起作用-'locals()'dict是快照,并且不会更新堆栈框架。

–亚当
19年6月14日在5:49

#5 楼

TL; DR

Python没有一元增减运算符(-- / ++)。相反,要增加值,请使用

a += 1


更多详细信息和注意事项

,但请注意此处。如果您来自C,即使在python中也是如此。 Python在C的意义上没有“变量”,而是python使用名称和对象,而在python中int是不可变的。

所以可以说你做到了

a = 1


这在python中的含义是:创建一个具有值int1类型的对象,并将名称a绑定到该对象。该对象是具有值int1的实例,名称a引用了该对象。名称a和它所引用的对象是不同的。

现在让您说您做

a += 1


由于int是不可变的,所以发生以下情况:


查找a所指的对象(它是ID为int0x559239eeb380
查找对象0x559239eeb380的值(它是1
将1添加到该值(1 + 1 = 2)
创建一个新的int对象,其值为2(其对象ID为0x559239eeb3a0
将名称a绑定到该新对象
现在,a引用对象0x559239eeb3a0,并且不再用名称0x559239eeb380引用原始对象(a)。如果没有其他名称引用原始对象,则稍后将对其进行垃圾回收。

尝试一下:

a = 1
print(hex(id(a)))
a += 1
print(hex(id(a)))


#6 楼


在Python中,与Common Lisp,Scheme或


Wikipedia

因此,通过引入此类运算符,您可以打破表达式/语句的分裂。

出于相同的原因,您不能像其他某些语言中那样,不能写

if x = 0:
  y = 1



/>

评论


有趣的是,此限制将在即将发布的Python 3.8中取消,并带有赋值表达式的新语法(PEP-572 python.org/dev/peps/pep-0572)。例如,如果(n:= len(a))> 10:y = n + 1,我们将能够写出。请注意,这种区别很明显,因为为此引入了新的运算符(:=)

– Zertrin
19年8月26日在9:34



#7 楼

是的,我也错过了++和-功能。数百万行的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 # <type 'int'> 323


...而这将保持c为类型计数器:

c = counter(100)
c.set(c + 223)
print type(c),c # <class '__main__.counter'> 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


#8 楼

在python 3.8+中,您可以执行以下操作:
(a:=a+1) #same as ++a (increment, then return new value)
(a:=a+1)-1 #same as a++ (return the incremented value -1) (useless)

您可以对此进行很多思考。
>>> a = 0
>>> while (a:=a+1) < 5:
    print(a)

    
1
2
3
4

或者如果您想使用更复杂的语法编写东西(目标是不是优化):
>>> del a
>>> while (a := (a if 'a' in locals() else 0) + 1) < 5:
    print(a)

    
1
2
3
4

即使'a'不存在且没有错误,也会返回0,然后将其设置为1

评论


伟大的答案!只是一个建议:a ++会增加但返回旧值,(a:= a + 1)更像是++ a会增加并返回新值。

–thiagola92
7月20日,0:41



#9 楼

python中没有像C之类的语言中的post / pre递增/ decre减运算符。

我们可以看到++--是多个符号相乘,就像我们在数学(-1)中一样*(- 1)=(+1)。

例如

---count


解析为

-(-(-count)))


哪个翻译成

-(+count)


,因为-符号与-符号的乘积是+

最后,

-count


评论


这说明其他答案没有什么意思?

–丹尼尔·B。
1月14日18:26

@DanielB。其他答案尚未说明内部发生了什么。而且,他们都没有告诉您写----- count时会发生什么。

–Optider
1月16日0:47

没有提及正在执行乘法运算,因此,我认为有一个要点,直截了当的答案对于其他用户很有用。如果您从中了解的话,就没有冒犯。学习比学习的来源更重要。

–Optider
1月17日4:15