Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python 2.7: Ints as objects

How does an int in python avoid being an object but yet is one:

If I do the following:

>>> dir(10)
['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__float__', '__floordiv__', '__format__', '__getattribute__', '__getnewargs__', '__hash__', '__hex__', '__index__', '__init__', '__int__', '__invert__', '__long__', '__lshift__', '__mod__', '__mul__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'imag', 'numerator', 'real']
>>> 10.__add__(20)
  File "<stdin>", line 1
    10.__add__(20)
             ^
SyntaxError: invalid syntax

If I type in 10. it produces 10.0 whereas anything such as 10.__ anything __ produces a syntax error. It does make sense since a float would be considered as 10.5 but

  1. how is this achieved/implemented?
  2. how can I call the int methods on an int?
like image 772
Har Avatar asked May 01 '15 11:05

Har


2 Answers

The Python tokenizer is greedy, it always tries to match the longest token possible at any given position; otherwise it could think that 10.e+123 is the same as (10).e + 123.

In the case of 10.__add__(20) it sees the following tokens:

>>> tokenize.tokenize(iter(['10.__add__(20)']).next)
1,0-1,3:        NUMBER  '10.'
1,3-1,10:       NAME    '__add__'
1,10-1,11:      OP      '('
1,11-1,13:      NUMBER  '20'
1,13-1,14:      OP      ')'
2,0-2,0:        ENDMARKER       ''

i.e., the . was considered to be a part of the number literal, e.g. a float. If you parenthesize the number ((10).__add__(20)), you'll get:

>>> tokenize.tokenize(iter(['(10).__add__(20)']).next)
1,0-1,1:        OP      '('
1,1-1,3:        NUMBER  '10'
1,3-1,4:        OP      ')'
1,4-1,5:        OP      '.'
1,5-1,12:       NAME    '__add__'
1,12-1,13:      OP      '('
1,13-1,15:      NUMBER  '20'
1,15-1,16:      OP      ')'
2,0-2,0:        ENDMARKER       ''

Similarly, just adding a space between the number and the dot (10 .) would work here.

Here the . is tokenized as a separate operator. If a float constant would do, then you could actually type:

10..__add__(20)

This is tokenized as float literal 10. followed by a . followed by identifier __add__ and so forth.


The silly iter().next needs to be iter().__next__ on Python 3. The tokenize.tokenize requires an argument that is a readline -like function; when called, it should return a line of program input.


Just use parenthesis around the number:

(10).__add__(20)
like image 31
Julien Spronck Avatar answered Oct 14 '22 10:10

Julien Spronck