7

How does evaluating + 5 work (spoiler alert: result is 5)?

Isn't the + working by calling the __add__ method on something? 5 would be "other" in:

>>> other = 5
>>> x = 1
>>> x.__add__(other)
6

So what is the "void" that allows adding 5?

void.__add__(5)

Another clue is that:

/ 5

throws the error:

TypeError: 'int' object is not callable
PascalVKooten
  • 20,643
  • 17
  • 103
  • 160
  • 3
    The latter `TypeError` has to do with IPython auto-parentheses feature, it substitutes `/whatever` with `whatever()`. Python has no unary `/` operator. – bereal May 24 '15 at 10:32
  • @bereal Any link to this feature? It is more than just auto-parenthesis: `/sum (1 2 3 4 5)` returns 15. – Ashwini Chaudhary May 24 '15 at 10:49
  • @AshwiniChaudhary described [here](https://ipython.org/ipython-doc/dev/interactive/reference.html#automatic-parentheses-and-quotes), (same as IPython's `?`-help). Apparently, it's a bit more advanced, than described, for example, `/'abc'` returns `'abc'`, I have no idea what that means. – bereal May 24 '15 at 10:52

3 Answers3

8

The + in this case calls the unary magic method __pos__ rather than __add__:

>>> class A(int):
    def __pos__(self):
        print '__pos__ called'
        return self
...
>>> a = A(5)
>>> +a
__pos__ called
5
>>> +++a
__pos__ called
__pos__ called
__pos__ called
5

Python only supports 4(unary arithmetic operations) of them __neg__, __pos__, __abs__, and __invert__, hence the SyntaxError with /. Note that __abs__ works with a built-in function called abs(), i.e no operator for this unary operation.


Note that /5 (/ followed by something)is interpreted differently by IPython shell only, for normal shell it is a syntax error as expected:

Ashwinis-MacBook-Pro:py ashwini$ ipy
Python 2.7.6 (default, Sep  9 2014, 15:04:36)
Type "copyright", "credits" or "license" for more information.

IPython 3.0.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.
>>> /5
Traceback (most recent call last):
  File "<ipython-input-1-2b14d13c234b>", line 1, in <module>
    5()
TypeError: 'int' object is not callable

>>> /float 1
1.0
>>> /sum (1 2 3 4 5)
15

Ashwinis-MacBook-Pro:~ ashwini$ python
Python 2.7.6 (default, Sep  9 2014, 15:04:36)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> /5
  File "<stdin>", line 1
    /5
    ^
SyntaxError: invalid syntax
>>> /float 1
  File "<stdin>", line 1
    /float 1
    ^
SyntaxError: invalid syntax
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • Not sure why you include `__abs__` along with the other 3 – wim May 24 '15 at 11:10
  • @wim `__abs__` has no unary operator but it is still considered an unary operation. – Ashwini Chaudhary May 24 '15 at 11:28
  • I don't think you're correct on that - the [docs define](https://docs.python.org/2/reference/expressions.html#unary-arithmetic-and-bitwise-operations) clearly a `u_expr` and mention only minus, plus, and invert operations. Why would you call `int.__abs__` a unary operation but not, say, `int.__nonzero__` or others?? – wim May 25 '15 at 00:43
  • 1
    @wim From Data model page(below [object.__invert__](https://docs.python.org/2/reference/datamodel.html#object.__invert__)): *Called to implement the unary arithmetic operations (`-`, `+`, `abs()` and `~`)*. – Ashwini Chaudhary May 25 '15 at 08:26
  • Well, there it is! Bizarre. Why they call it an "operation" when there is no operator makes no sense for me. And they even explicitly then give a function call along with the 3 operators .. *shrugs* – wim May 25 '15 at 11:43
  • [As far as I could tell](http://stackoverflow.com/q/22387166/674039) there was never an operator for abs in python, and yet there is the apparently useless `operator.abs` also in existence. Maybe there were once plans to add a syntax for it, and they got shelved. – wim May 25 '15 at 11:45
7

It looks like you've found one of the three unary operators:

  • The unary plus operation +x calls the __pos__() method.
  • The unary negation operation -x calls the __neg__() method.
  • The unary not (or invert) operation ~x calls the __invert__() method.
Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485
6

Per the language reference on numeric literals:

Note that numeric literals do not include a sign; a phrase like -1 is actually an expression composed of the unary operator - and the literal 1.

And the section on unary operators:

The unary - (minus) operator yields the negation of its numeric argument.

The unary + (plus) operator yields its numeric argument unchanged.

There is no unary / (divide) operator, hence the error.

The related "magic methods" (__pos__, __neg__) are covered in the data model documentation.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437