1043

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

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

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
Ashwin Nanjappa
  • 76,204
  • 83
  • 211
  • 292
  • 1
    Chris: You have answered my query (the what). In addition, I would like to know why Python differs in this behavior from C/C++. – Ashwin Nanjappa Sep 28 '09 at 08:04
  • 24
    Python is not C or C++. Different design decisions went into making the language. In particular, Python deliberately does not define assignment operators that can be used in an arbitrary expression; rather, there are assignment statements and augmented assignment statements. See reference below. – Ned Deily Sep 28 '09 at 08:22
  • 43
    Kaizer: Coming from C/C++, I write ++count and it compiles in Python. So, I thought the language has the operators. – Ashwin Nanjappa Sep 28 '09 at 09:47
  • I believe that ++ exists in C mainly because it's syntactic sugar for pointer arithmetic, e.g. the classic `while (dest++ = src++) {;}`. – Mark E. Haase Apr 22 '12 at 17:19
  • 4
    given that most contemporary OOP languages had these symbols when GVR came up with Python, wouldn't it make sense to include a syntax warning for this construct? – Fox May 03 '14 at 06:44
  • 9
    @mehaase ++ and -- don't exist in c "as syntactic sugar for pointer arithmetic", they exist because many processors have automatic increment and decrement memory access mechanisms (in general pointer indexing, stack indexing) as part of their native instruction set. For instance, in 6809 assembler: `sta x++` ...the atomic instruction that results stores the `a` accumulator where `x` is pointing, then increments `x` by the size of the accumulator. This is done because it is faster than pointer arithmetic, because it is very common, and because it's easy to understand. Both pre- and -post. – fyngyrz Oct 28 '16 at 13:16
  • @fyngyrz for x86 there are actually instructions for increment and decrement and that is why (*and how C interprets*) `++` and `--` exist in C, it's not just *"syntactic sugar for pointer arithmetic"*. `i++` and `i += 1` are not the same. Check [inc](https://c9x.me/x86/html/file_module_x86_id_140.html) and [dec](https://c9x.me/x86/html/file_module_x86_id_71.html) x86 instructions. – Christos Lytras Jan 01 '20 at 00:31
  • @christos-lytras - that's pretty much exactly what I said. You're responding to the wrong person. – fyngyrz Jan 01 '20 at 21:19
  • @christos-lytras - _also_ - x++ --y, etc. long, _long_ predate the x86 instruction set. For instance, the 6809 had an awesome set of auto-inc and auto-dec indexing/stackop modes as well as inc, dec, add, subtract and so on. – fyngyrz Feb 08 '20 at 19:38
  • @fyngyrz yes, it always depends on the compiler and for what instruction set (*assembler, processor architecture*) is build for. If it doesn't have any kind of increment instruction then it will use the addition instructions. Languages are agnostic when it comes to how the compilers *translate* the code. – Christos Lytras Feb 09 '20 at 08:42
  • Have you tried `+count`, `---count` and `+-+-+count`? These also "compile", but what are they supposed to do? – bers May 06 '20 at 12:18

11 Answers11

1312

++ 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.
Ayşe Nur
  • 493
  • 7
  • 11
Chris Lutz
  • 73,191
  • 16
  • 130
  • 183
  • 15
    "The + operator is the "identity" operator, which does nothing." Only for numeric types; for other type it is an error by default. – newacct Sep 28 '09 at 07:47
  • 4
    Right. But then again, `++` and `--` should only be expected to work on numeric types. – Chris Lutz Sep 28 '09 at 07:49
  • 50
    Also, be aware that, in Python, += and friends are not operators that can be used in expressions. Rather, in Python they are defined as part of an "augmented assignment statement". This is consistent with the language design decision in Python to not allow assignment ("=") as an operator within arbitrary expressions, unlike what one can do in C. See http://docs.python.org/reference/simple_stmts.html#augmented-assignment-statements – Ned Deily Sep 28 '09 at 08:06
  • 17
    The unary `+` operator has a use. For decimal.Decimal objects, it rounds to current precision. – u0b34a0f6ae Sep 28 '09 at 09:10
  • 1
    Kaizer, that is an odd use for +. Any idea why Python does that for decimal.Decimal objects? – Ashwin Nanjappa Sep 29 '09 at 02:16
  • Chris, thanks so much for this detailed answer! I learnt a lot just by reading and understanding your explanation :-) – Ashwin Nanjappa Sep 29 '09 at 02:17
  • 23
    I'm betting on parser simplification. Note an item in [PEP 3099](http://www.python.org/dev/peps/pep-3099/), "Things that will Not Change in Python 3000": "The parser won't be more complex than LL(1). Simple is better than complex. This idea extends to the parser. Restricting Python's grammar to an LL(1) parser is a blessing, not a curse. It puts us in handcuffs that prevent us from going overboard and ending up with funky grammar rules like some other dynamic languages that will go unnamed, such as Perl." I don't see how to disambiguate `+ +` and `++` without breaking LL(1). – Mike DeSimone Oct 14 '10 at 19:42
  • 1
    This must be _the_ reference question that all other "why doesn't Python have `++` operators?" questions get closed as duplicates of, because this answer accounts for 4% of my reputation. – Chris Lutz Mar 02 '12 at 03:01
  • 5
    This answer is correct so +1 but this is just another one of those annoyances with Python that have made me come to really dislike it. `strip()` instead of `trim()` like every other languages, no switches, some OO functions and some not ([`len(s)`](http://stackoverflow.com/a/237150/156755) vs [`s.lower()`](http://stackoverflow.com/a/6797990/156755)). Very frustrating and inconsistent language – Basic Aug 05 '13 at 10:02
  • 1
    For anyone who was, like me, at a loss as to what the purpose of the unary + operator is, it's the opposite of the unary - operator. What is -1? It's negative one. What is +1? It's positive one. What is +(+1)? It's still positive one. Feel stupid for having wondered now? Me too. – ArtOfWarfare Sep 23 '13 at 18:00
  • @Basic the beauty of python's built-in functions, such as `len()`, is they usually map to a method in the object, allowing you to override or give power to the built-in's for any of your own classes -- `s.__len__()` in this case. – CivFan May 15 '15 at 00:00
  • 3
    @CivFan Why is that any more desirable than inheriting from an object that has a length method/property that can be overridden? As far as I can see, it simply adds a layer of indirection for no tangible benefit – Basic May 15 '15 at 08:15
  • @Basic But.. that's precisely what's happening. This leads into something else beautiful about python, a public, private, protected method scheme enforced by consistent coding style, rather than strictly enforced. `s.__len__()` is there when you really want to override it, but hidden away not cluttering the vast majority of classes that have no need for it. – CivFan May 15 '15 at 13:15
  • 4
    @CivFan then a) `__len__()` isn't really private, it's just public but called via indiretion and b) we now need to know all the global methods that call the private methods when the object could've just had a `length()` method which could be overriden if desired. – Basic May 15 '15 at 15:00
  • @Basic precisely on both accounts! `__len__()` is not really private, but looks like it when you don't need it, and only there when you need it. When you introspect an object for useful methods, you don't end up finding an undefined `length()` and a hundred other undefined built-in methods. But that one time you do, it's still there under the covers. I need a drink. ;) – CivFan May 15 '15 at 15:11
  • 2
    @CivFan I think we'll have to agree to disagree, I still think it looks like noise and breaks OO principles for little benefit, if any. For all that, I need a drink too. Have a nice weekend – Basic May 15 '15 at 15:16
  • 4
    'Python likes to eliminate language "gotcha"-s' - isn't this a language gotcha? – Nick Mertin Sep 14 '15 at 21:22
  • how to increment/decrement a recordset ? [link](http://stackoverflow.com/questions/39081083/how-to-increment-or-decrement-a-recordset-odoo9) – maharshi Aug 22 '16 at 14:15
  • 11
    It's not correct to say that `++` is nothing more than a synonym for `+= 1`. There are pre-increment and post-increment variants of ++ so it is clearly not the same thing. I agree with the rest of your points, though. – PhilHibbs May 17 '17 at 08:59
  • 1
    Just for this, your are my idol: "C compilers were stupid and didn't know how to optimize a += 1" – Jimmy Dec 13 '17 at 04:14
  • 4
    Each to their own. I use ++ and -- all the time and don't end up messing anything up. Python is an OK language, but it has many flaws and I find the community over religious about various language constructs. Its a tool, not the Mona Lisa. Lets get the job done and move on to the next task ... which will most probably be written in R, or Matlab or C++ –  Mar 05 '18 at 15:41
  • 1
    To future-proof @NedDeily's highly up-voted remark on assignments, Python 3.8 allows assignment nearly anywhere with the new `:=` operator. – Benoît P Feb 25 '19 at 21:08
  • "why does Python even have this unary operator? It exists only to complement the – operator if you need to overload these operators for your own classes. (See the documentation for the __pos__ special method.)" From: https://inventwithpython.com/blog/2018/05/21/pythons-fake-increment-and-decrement-operators/ – Manuel Alves Dec 02 '20 at 13:17
445

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.

Lennart Regebro
  • 167,292
  • 41
  • 224
  • 251
  • 97
    That example is wrong (and you're probably confusing immutability with identity) - they have the same id due to some vm optimization that uses the same objects for numbers till 255 (or something like that). Eg (bigger numbers): >>> a = 1231231231231 >>> b = 1231231231231 >>> id(a), id(b) (32171144, 32171168) – ionelmc Jan 11 '10 at 01:00
  • 68
    The immutability claim is spurious. Conceptually, `i++` would mean to assign `i + 1` to the *variable* `i`. `i = 5; i++` means to assign `6` to `i`, not modify the `int` object pointed to by `i`. That is, it does not mean to [increment the value of `5`](http://mathworld.wolfram.com/SufficientlyLarge.html)! – Mechanical snail Sep 20 '11 at 04:19
  • 3
    @Mechanical snail: In which case it would not be increment operators at all. And then the += operator is clearer, more explicit, more flexible and does the same thing anyway. – Lennart Regebro Sep 20 '11 at 05:35
  • 8
    @LennartRegebro: In C++ and Java, `i++` only operates on lvalues. If it were intended to increment the object pointed to by `i`, this restriction would be unnecessary. – Mechanical snail Sep 20 '11 at 07:18
  • 3
    Immutability is indeed irrelevant in this case. Consider: Clojure has a built-in increment operator and all data structures are immutable by default. While it's true you get a new reference to the new value, that's mostly orthogonal to the purely syntactic choice of `++` vs. `+= 1`. – charleslparker Jan 30 '13 at 18:26
  • let us [keep any further repetition of the same old arguments in chat](http://chat.stackoverflow.com/rooms/36452/discussion-between-lennart-regebro-and-tarik) – Lennart Regebro Aug 29 '13 at 10:20
  • 1
    **Moderator note:** Comments are not for extended discussion. Please use chat for that. – Martijn Pieters Aug 26 '21 at 12:32
  • Please read [this reply why Guido didn't define `++` operators](https://stackoverflow.com/a/3654936/548792). Deliberating on the **immutability** of built-in types is irrelevant, while the post misses the point of `++` being an _expression_ while `+=1` is a _statement_. – ankostis Mar 20 '23 at 08:58
58

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)
glglgl
  • 89,107
  • 13
  • 149
  • 217
24

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)))
RBF06
  • 2,013
  • 2
  • 21
  • 20
  • apart from the fact that small integers are 'interned', so they will never be garbage collected. – Tony Suffolk 66 Dec 31 '20 at 08:30
  • What you're calling 'names' are commonly called variables (including by Mr Rossum) across programming languages. They may have different scope and lifetime and more relaxed typing rules in dynamic languages like Python (Lisp, JavaScript, Lua, etc.) As @TonySuffolk66 points out, they aren't actually always references to GC'able objects - and a C/C++ variable may hold a reference to an object, and as in Python, such an object may be shared between variables, and GC'd when there are no more references to it. – Spike0xff Feb 22 '22 at 19:36
  • You are correct that Guido talks about variables, but when you look at any documentation that looks at the internal semantics you will see that the details talk about names bound to objects. It is a minor distinction for most developers but an important one when you start talking about the impact on objects of operations. – Tony Suffolk 66 Feb 28 '22 at 07:43
22

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

Henry
  • 577
  • 4
  • 9
15

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.

Piotr Dabkowski
  • 5,661
  • 5
  • 38
  • 47
  • 1
    Note: while great, these helper methods will not work if your locals exist on class function stack frame. i.e - calling them from within a class method def will not work - the 'locals()' dict is a snapshot, and does not update the stack frame. – Adam Jun 14 '19 at 05:49
12

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.

Vitalii Fedorenko
  • 110,878
  • 29
  • 149
  • 111
  • Interestingly, this restriction will be lifted in the upcoming release Python 3.8 with the new syntax for Assignment expressions (PEP-572 https://www.python.org/dev/peps/pep-0572/). We will be able to write `if (n := len(a)) > 10: y = n + 1` for example. Note that the distinction is clear because of the introduction of a new operator for that purpose (`:=`) – Zertrin Aug 26 '19 at 09:34
8

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
fyngyrz
  • 2,458
  • 2
  • 36
  • 43
3

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
B--rian
  • 5,578
  • 10
  • 38
  • 89
Optider
  • 550
  • 4
  • 11
  • 1
    What does this say that other answers don't? – Daniel B. Jan 14 '20 at 18:26
  • @DanielB. Other answers haven't told what happens internally. And, neither they have told what will happen when you will write `-----count`. – Optider Jan 16 '20 at 00:47
  • 2
    There isn't any mention that multiplication is being carried out, so I thought a consice and to the point answer would be useful for fellow users. No offense if you understood from that. Learning is more important than the source where you learn from. – Optider Jan 17 '20 at 04:15
0

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.

kishi
  • 59
  • 1
  • 5
  • Using tricks to change the syntax of a language is exactly the kind of things you shouldn't do, in my opinion. – kuroi neko Jan 08 '23 at 19:27
-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.

Nicow
  • 445
  • 4
  • 7
  • -1, the lambda workaround works just once - it always return 1. And the search&replace also doesn't work for all cases - consider `if (c++): ...` – Fosfor Feb 19 '22 at 01:23