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

发布于 2024-08-06 04:20:48 字数 109 浏览 9 评论 0原文

如何使用预自增/自减运算符(++--),就像在 C++ 中一样?

为什么++count运行,但不改变变量的值?

How do I use pre-increment/decrement operators (++, --), just like in C++?

Why does ++count run, but not change the value of the variable?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

清醇 2024-08-13 04:20:48

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

++count

解析为

+(+count)

翻译为

count

你必须使用稍长的 += 运算符来完成你想做的事情:

count += 1

我怀疑 ++-- 运算符。我不知道 Guido van Rossum 为该决定给出的确切论点,但我可以想象一些论点:

  • 更简单的解析。从技术上讲,解析 ++count 是不明确的,因为它可能是 ++count(两个一元 < code>+ 运算符)就像 ++count(一个一元 ++ 运算符)一样简单。这不是一个重大的语法歧义,但它确实存在。
  • 语言更简单。 ++只不过是+= 1的同义词。这是一种简写形式,因为 C 编译器很愚蠢,不知道如何将 a += 1 优化为大多数计算机都有的 inc 指令。在优化编译器和字节码解释语言的今天,向语言添加运算符以允许程序员优化其代码通常是不受欢迎的,尤其是在像 Python 这样被设计为一致和可读的语言中。
  • 令人困惑的副作用。使用 ++ 运算符的语言中一个常见的新手错误是混淆了前后递增/递减运算符之间的差异(优先级和返回值),而 Python 喜欢消除语言“陷阱”-s。 优先级问题 C 中的前置/后置增量 非常复杂,而且非常容易搞乱。

++ is not an operator. It is two + operators. The + operator is the identity operator, which does nothing. (Clarification: the + and - unary operators only work on numbers, but I presume that you wouldn't expect a hypothetical ++ operator to work on strings.)

++count

Parses as

+(+count)

Which translates to

count

You have to use the slightly longer += operator to do what you want to do:

count += 1

I suspect the ++ and -- operators were left out for consistency and simplicity. I don't know the exact argument Guido van Rossum gave for the decision, but I can imagine a few arguments:

  • Simpler parsing. Technically, parsing ++count is ambiguous, as it could be +, +, count (two unary + operators) just as easily as it could be ++, count (one unary ++ operator). It's not a significant syntactic ambiguity, but it does exist.
  • Simpler language. ++ is nothing more than a synonym for += 1. It was a shorthand invented because C compilers were stupid and didn't know how to optimize a += 1 into the inc instruction most computers have. In this day of optimizing compilers and bytecode interpreted languages, adding operators to a language to allow programmers to optimize their code is usually frowned upon, especially in a language like Python that is designed to be consistent and readable.
  • Confusing side-effects. One common newbie error in languages with ++ operators is mixing up the differences (both in precedence and in return value) between the pre- and post-increment/decrement operators, and Python likes to eliminate language "gotcha"-s. The precedence issues of pre-/post-increment in C are pretty hairy, and incredibly easy to mess up.
泅人 2024-08-13 04:20:48

Python 没有前置和后置增量运算符。

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

>>> b = 5
>>> a = 5
>>> id(a)
162334512
>>> id(b)
162334512
>>> a is b
True

上面的 a 和 b 实际上是同一个对象。如果你增加 a,你也会增加 b。那不是你想要的。所以你必须重新分配。像这样:

b = b + 1

许多使用 python 的 C 程序员想要一个递增运算符,但该运算符看起来像是递增了对象,而实际上是重新分配了对象。因此,添加了 -=+= 运算符,比 b = b + 1 更短,同时比 b = b + 1 更清晰、更灵活b++,所以大多数人都会用以下方式递增:

b += 1

这会将 b 重新分配给 b+1。这不是一个递增运算符,因为它不会递增 b,而是重新分配它。

简而言之:Python 在这里的行为有所不同,因为它不是 C,也不是机器代码的低级包装器,而是一种高级动态语言,其中增量没有意义,也不像 C 那样必要,例如,每次有循环时都使用它们。

Python does not have pre and post increment operators.

In Python, integers are immutable. That is you can't change them. This is because the integer objects can be used under several names. Try this:

>>> b = 5
>>> a = 5
>>> id(a)
162334512
>>> id(b)
162334512
>>> a is b
True

a and b above are actually the same object. If you incremented a, you would also increment b. That's not what you want. So you have to reassign. Like this:

b = b + 1

Many C programmers who used python wanted an increment operator, but that operator would look like it incremented the object, while it actually reassigns it. Therefore the -= and += operators where added, to be shorter than the b = b + 1, while being clearer and more flexible than b++, so most people will increment with:

b += 1

Which will reassign b to b+1. That is not an increment operator, because it does not increment b, it reassigns it.

In short: Python behaves differently here, because it is not C, and is not a low level wrapper around machine code, but a high-level dynamic language, where increments don't make sense, and also are not as necessary as in C, where you use them every time you have a loop, for example.

亚希 2024-08-13 04:20:48

虽然其他答案就其显示的仅 + 通常的作用而言是正确的(即,如果数字是一个,则保持原样),但就其不完整而言,它们是不完整的不解释发生了什么。

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

While the others answers are correct in so far as they show what a mere + usually does (namely, leave the number as it is, if it is one), they are incomplete in so far as they don't explain what happens.

To be exact, +x evaluates to x.__pos__() and ++x to x.__pos__().__pos__().

I could imagine a VERY weird class structure (Children, don't do this at home!) like this:

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))
﹏雨一样淡蓝的深情 2024-08-13 04:20:48

在 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

In python 3.8+ you can do :

(a:=a+1) #same as ++a (increment, then return new value)
(a:=a+1)-1 #same as a++ (return the incremented value -1) (useless)

You can do a lot of thinks with this.

>>> a = 0
>>> while (a:=a+1) < 5:
    print(a)

    
1
2
3
4

Or if you want write somthing with more sophisticated syntaxe (the goal is not optimization):

>>> del a
>>> while (a := (a if 'a' in locals() else 0) + 1) < 5:
    print(a)

    
1
2
3
4

It will return 0 even if 'a' doesn't exist without errors, and then will set it to 1

围归者 2024-08-13 04:20:48

TL;DR

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

a += 1

更多细节和陷阱,

但这里要小心。如果你来自 C,即使这在 python 中也是不同的。 Python 没有 C 那样的“变量”,相反,Python 使用名称和对象,并且在 Python 中,int 是不可变的。

所以让我们说你要做的

a = 1

这在Python中意味着:创建一个具有值1int类型的对象并将名称a绑定到它。 objectint 的一个实例,值为 1name a指的是它。名称a 和它所引用的对象是不同的。

现在假设您这样做

a += 1

由于 int 是不可变的,因此这里发生的情况如下:

  1. 查找 a 引用的对象(它是一个 int 和 id 0x559239eeb380
  2. 查找对象 0x559239eeb380 的值(它是 1
  3. 将该值加 1 (1 + 1 = 2 )
  4. 创建一个值为 2 int 对象(它的对象 ID 0x559239eeb3a0
  5. 重新绑定名称 a 指向这个新对象
  6. 现在 a 引用对象 0x559239eeb3a0 并且原始对象 (0x559239eeb380) 不再被引用命名a。如果没有任何其他名称引用原始对象,稍后它将被垃圾收集。

自己尝试一下:

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

TL;DR

Python does not have unary increment/decrement operators (--/++). Instead, to increment a value, use

a += 1

More detail and gotchas

But be careful here. If you're coming from C, even this is different in python. Python doesn't have "variables" in the sense that C does, instead python uses names and objects, and in python ints are immutable.

so lets say you do

a = 1

What this means in python is: create an object of type int having value 1 and bind the name a to it. The object is an instance of int having value 1, and the name a refers to it. The name a and the object to which it refers are distinct.

Now lets say you do

a += 1

Since ints are immutable, what happens here is as follows:

  1. look up the object that a refers to (it is an int with id 0x559239eeb380)
  2. look up the value of object 0x559239eeb380 (it is 1)
  3. add 1 to that value (1 + 1 = 2)
  4. create a new int object with value 2 (it has object id 0x559239eeb3a0)
  5. rebind the name a to this new object
  6. Now a refers to object 0x559239eeb3a0 and the original object (0x559239eeb380) is no longer refered to by the name a. If there aren't any other names refering to the original object it will be garbage collected later.

Give it a try yourself:

a = 1
print(hex(id(a)))
a += 1
print(hex(id(a)))
时光匆匆的小流年 2024-08-13 04:20:48

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 does not have these operators, but if you really need them you can write a function having the same functionality.

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

Usage:

x = 1
y = PreIncrement('x') #y and x are both 2
a = 1
b = PostIncrement('a') #b is 1 and a is 2

Inside a function you have to add locals() as a second argument if you want to change local variable, otherwise it will try to change global.

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()

Also with these functions you can do:

x = 1
print(PreIncrement('x'))   #print(x+=1) is illegal!

But in my opinion following approach is much clearer:

x = 1
x+=1
print(x)

Decrement operators:

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

I used these functions in my module translating javascript to python.

生来就爱笑 2024-08-13 04:20:48

在Python中,表达式和语句之间有严格的区别
与 Common Lisp、Scheme 或等语言相反
红宝石。

Wikipedia

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

出于同样的原因,您无法

if x = 0:
  y = 1

像其他一些不保留这种区别的语言一样进行书写。

In Python, a distinction between expressions and statements is rigidly
enforced, in contrast to languages such as Common Lisp, Scheme, or
Ruby.

Wikipedia

So by introducing such operators, you would break the expression/statement split.

For the same reason you can't write

if x = 0:
  y = 1

as you can in some other languages where such distinction is not preserved.

ㄟ。诗瑗 2024-08-13 04:20:48

是的,我也错过了 ++ 和 -- 功能。几百万行的 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

......或者,更详细、更明确地表达我们真正想要发生的事情,尽管在实际形式中通过冗长反驳了(使用 cv 代替)......

c = counter(42)
s = '%s: %d' % ('Expecting 42',c.__getitem__()) # and getting 42.
print s

Yeah, I missed ++ and -- functionality as well. A few million lines of c code engrained that kind of thinking in my old head, and rather than fight it... Here's a class I cobbled up that implements:

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

Here '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

You might use it like this:

c = counter()                          # defaults to zero
for listItem in myList:                # imaginary task
     doSomething(c.postinc(),listItem) # passes c, but becomes c+1

...already having c, you could do this...

c.set(11)
while c.predec() > 0:
    print c

....or just...

d = counter(11)
while d.predec() > 0:
    print d

...and for (re-)assignment into integer...

c = counter(100)
d = c + 223 # assignment as integer
c = c + 223 # re-assignment as integer
print type(c),c # <type 'int'> 323

...while this will maintain c as type counter:

c = counter(100)
c.set(c + 223)
print type(c),c # <class '__main__.counter'> 323

EDIT:

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

...because inside that tuple, getitem() isn't what used, instead a reference to the object is passed to the formatting function. Sigh. So:

c = counter(42)
s = '%s: %d' % ('Expecting 42',c.v) # and getting 42.
print s

...or, more verbosely, and explicitly what we actually wanted to happen, although counter-indicated in actual form by the verbosity (use c.v instead)...

c = counter(42)
s = '%s: %d' % ('Expecting 42',c.__getitem__()) # and getting 42.
print s
哀由 2024-08-13 04:20:48

python 中没有像 C 等语言那样的后/前递增/递减运算符。

我们可以将 ++-- 视为多个符号相乘,就像我们在数学 (-1) * (-1) = (+1)。

例如

---count

解析为

-(-(-count)))

Which 翻译为

-(+count)

因为, - 符号与 - 符号相乘是 +

最后,

-count

There are no post/pre increment/decrement operators in python like in languages like C.

We can see ++ or -- as multiple signs getting multiplied, like we do in maths (-1) * (-1) = (+1).

E.g.

---count

Parses as

-(-(-count)))

Which translates to

-(+count)

Because, multiplication of - sign with - sign is +

And finally,

-count
心房敞 2024-08-13 04:20:48

扩展亨利的答案,我实验性地实现了一个实现a++的语法糖库:hdytto

使用方法很简单。从 PyPI 安装后,将 sitecustomize.py: 放入

from hdytto import register_hdytto
register_hdytto()

您的项目目录中。然后,制作 main.py:

# coding: hdytto

a = 5
print(a++)
print(++a)
b = 10 - --a
print(b--)

并通过 PYTHONPATH= 运行它。 python main.py。 输出将是hdytto 将 a++ 替换为 ((a:=a+1)-1),因此它可以工作。

5
7
4

解码脚本文件时,

Extending Henry's answer, I experimentally implemented a syntax sugar library realizing a++: hdytto.

The usage is simple. After installing from PyPI, place sitecustomize.py:

from hdytto import register_hdytto
register_hdytto()

in your project directory. Then, make main.py:

# coding: hdytto

a = 5
print(a++)
print(++a)
b = 10 - --a
print(b--)

and run it by PYTHONPATH=. python main.py. The output will be

5
7
4

hdytto replaces a++ as ((a:=a+1)-1) when decoding the script file, so it works.

半步萧音过轻尘 2024-08-13 04:20:48

一个直接的解决方法

c = 0
c = (lambda c_plusplus: plusplus+1)(c)
print(c)
1

不再打字

 c = c + 1

另外,你可以直接写
由 小码哥发布于
并完成所有代码,然后搜索/替换“c++”,替换为“c=c+1”。只需确保正则表达式搜索已关闭即可。

A straight forward workaround

c = 0
c = (lambda c_plusplus: plusplus+1)(c)
print(c)
1

No more typing

 c = c + 1

Also, you could just write
c++
and finish all your code and then do search/replace for "c++", replace with "c=c+1". Just make sure regular expression search is off.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文