首页 文章

Python中递增和递减运算符的行为

提问于
浏览
636

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

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

为什么Python偏离了C / C中这些运算符的行为?

6 回答

  • 9

    ++ 不是运营商 . 这是两个 + 运营商 . + 运算符是 identity 运算符,它什么都不做 . (澄清: +- 一元运算符只适用于数字,但我认为你不会指望一个假设的 ++ 运算符来处理字符串 . )

    ++count
    

    解析为

    +(+count)
    

    这转化为

    count
    

    您必须使用稍长的 += 运算符来执行您想要执行的操作:

    count += 1
    

    我怀疑 ++-- 运营商因为一致性和简单性而被排除在外 . 我不知道Guido van Rossum给出的确切论据,但我可以想象一些论点:

    • 更简单的解析 . 从技术上讲,解析 ++count 是不明确的,因为它可能是 ++count (两个一元 + 运算符),就像 ++count (一个一元 ++ 运算符)一样容易 . 这不是一个重要的句法歧义,但确实存在 .

    • 更简单的语言 . ++ 只不过是 += 1 的同义词 . 这是一个发明的简写,因为C编译器是愚蠢的,并且不知道如何优化 a += 1 到大多数计算机的 inc 指令 . 在优化编译器和字节码解释语言的这一天,向一种语言添加运算符以允许程序员优化其代码通常是不受欢迎的,特别是在像Python这样设计为一致且可读的语言中 .

    • 令人困惑的副作用 . 使用 ++ 运算符的语言中的一个常见新手错误是混合了增量前/减值运算符之间的差异(优先级和返回值),Python喜欢消除语言"gotcha" -s . pre-/post-increment in Cpre-/post-increment in C非常毛茸茸,非常容易搞砸 .

  • 829

    虽然其他答案是正确的,只要它们显示通常只是 + (即,保留数字,如果它是一个),它们是不完整的,因为他们不解释会发生什么 .

    确切地说, +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)
    
  • 8

    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 .

  • 46

    在Python中,与Common Lisp,Scheme或Ruby等语言相比,严格执行表达式和语句之间的区别 .

    Wikipedia

    因此,通过引入这样的运算符,您将破坏表达式/语句拆分 .

    出于同样的原因你不能写

    if x = 0:
      y = 1
    

    正如你可以在其他语言中那样,不保留这种区别 .

  • 345

    是的,我错过了 - 功能也是如此 . 几百万行的c代码在我的老头脑中刻上了那种想法,而不是对抗它......这是我练习的一个类:

    pre- and post-increment, pre- and post-decrement, addition,
    subtraction, multiplication, division, results assignable
    as integer, printable, settable.
    

    这是'tis:

    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
    

    编辑:

    And then there's this bit of unexpected (and thoroughly unwanted) behavior

    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
    
  • 4

    如果要增加或减少,通常需要对整数执行此操作 . 像这样:

    b++
    

    但在Python中,整数是 immutable . 那就是你无法改变它们 . 这是因为整数对象可以在多个名称下使用 . 试试这个:

    >>> 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中那样必要例如,每次有循环时都使用它们 .

相关问题