5
In [476]: 3 + 5
Out[476]: 8

In [477]: 3 +++++++++++++++++++++ 5
Out[477]: 8

In [478]: 3 + + + + + + + + + + + 5
Out[478]: 8

In [479]: 3 +++ --- +++ --- +++ 5
Out[479]: 8

Why there is no SyntaxError: invalid syntax or TypeError: bad operand type for unary + error?

I know this handled in compile process, but how it works?

mrk
  • 8,059
  • 3
  • 56
  • 78
Leo Howell
  • 71
  • 6

4 Answers4

6

Using ast module we can create abstract syntax tree presentation and see what happens:

import ast
source = 'ADD SOURCE HERE'
node = ast.parse(source, mode='eval')
ast.dump(node, False, False)

In the case of 3 +++ 5, AST generates the following expression:

'Expression(BinOp(Num(1), Add(), UnaryOp(UAdd(), UnaryOp(UAdd(), Num(2)))))'

Or for example 3 ++ -- 5 produces:

'Expression(BinOp(Num(3), Add(), UnaryOp(UAdd(), UnaryOp(USub(), Num(-5)))))'
jsalonen
  • 29,593
  • 15
  • 91
  • 109
  • I wonder if 3 ------------ 5 takes longer to calculate than 3 - 5. I don't have time to benchmark now... – zmbq Jun 25 '17 at 07:22
  • 2
    @zmbq yes, it does. the disassembly shows that `UNARY_NEGATIVE` is called several times. – hiro protagonist Jun 25 '17 at 07:35
  • I guess Python can't be sure that `--x == x` – zmbq Jun 25 '17 at 11:21
  • @zmbq As Hiro described in the other answer, Python can't optimize those since operators can be overloaded. And for that reason `--x` may not always be equal to`x` -- that must be determined in runtime. – jsalonen Jun 25 '17 at 12:54
5

Beause if there are more than one operator between operand then it will work as below

3 +++ 5  # it will work as 3 + ( + ( +5) )

Hope it clears your doubt.

Jay Parikh
  • 2,419
  • 17
  • 13
  • 2
    It is worth mentioning that `3 -- 5` produces `8`, while `3 --- 5` is `-2`, so obviously unary operators `+` and `-` work exactly as expected. – Błotosmętek Jun 25 '17 at 07:14
3
+ obj

will call the unary __pos__(self) (just as - obj calls __neg__(self). repeated + and - before obj will call those repeatedly.

++++++-+++++ 5  # = -5

in your expression

3 +++++++++++++++++++++ 5

the left-most operator will then call the binary __add__ (or __sub__). so there is no ambiguity and no reason for this to raise an error.

the python interpreter does not optimize these calls (which probably has to do with the fact that you can overload __pos__ and __neg__ to do pretty much whatever you want...):

from dis import dis

def f(x, y):
    return x ++--++ y

dis(f)

prints:

  4           0 LOAD_FAST                0 (x)
              3 LOAD_FAST                1 (y)
              6 UNARY_POSITIVE
              7 UNARY_POSITIVE
              8 UNARY_NEGATIVE
              9 UNARY_NEGATIVE
             10 UNARY_POSITIVE
             11 BINARY_ADD
             12 RETURN_VALUE
hiro protagonist
  • 44,693
  • 14
  • 86
  • 111
1

The expression is the same as:

3+(+(+5))

Any numeric expression can be preceded by - to make it negative:

5-(-(3)) = 5-(-3)
         = 5+3
         = 8

and

5-(-(-3)) = 5-(3)
          = 2

In Python, there are no increment operators like ++ and --

in C, which was probably the source of your confusion. To increment or decrement a variable i or j in Python use this style:

i += 1
j -= 1
mrk
  • 8,059
  • 3
  • 56
  • 78