Access to attributes on literals works on all types, but not `int`; What for?

I read that everything in python is an object, and so I started experimenting with different types and calling __str__ on them - at first I was very excited, but then I was embarrassed.

 >>> "hello world".__str__() 'hello world' >>> [].__str__() '[]' >>> 3.14.__str__() '3.14' >>> 3..__str__() '3.0' >>> 123.__str__() File "<stdin>", line 1 123.__str__() ^ SyntaxError: invalid syntax 
  • Why does something.__str__() work for "everything" except int ?
  • Is 123 not an object of type int ?
+46
python language-lawyer
Oct 10 '15 at 12:55
source share
4 answers

So you think you can dance with a floating point?

123 is the same part of the object as 3.14 , the “problem” lies in the grammar rules of the language; the parser thinks we're going to define a float - not an int with a method callback.

We get the expected behavior if we wrap the number in brackets, as shown below.

 >>> (123).__str__() '123' 

Or if we just add spaces after 123 :

 >>> 123 .__str__() '123' 


The reason it doesn't work for 123.__str__() is because the dot following 123 is interpreted as the decimal point of some partially declared floating point.

 >>> 123.__str__() File "", line 1 123.__str__() ^ SyntaxError: invalid syntax 

The parser tries to interpret __str__() as a sequence of numbers, but obviously does not work - and we get a SyntaxError, basically saying that the parser stumbled upon something that it did not expect.





Development

When viewing 123.__str__() python analyzer can use either 3 characters and interpret these 3 characters as an integer, or , it can use 4 characters and interpret them as start with a floating point.

 123.__str__() ^^^ - int 
 123.__str__() ^^^^- start of floating-point 

Just as a little child would like as much cake as possible on his plate, the parser is greedy and would like to learn as much as he can all at once; even if it’s not always the best of ideas, since the last (“best”) alternative has been chosen.

When he later realizes that __str__() cannot in any way be interpreted as floating point decimal, it is too late; SyntaxError.

Note

  123 .__str__() # works fine 

In the above snippet, 123 (note the space) must be interpreted as an integer, since the number cannot contain spaces. This means that it is semantically equivalent to (123).__str__() .

Note

  123..__str__() # works fine 

The above also works because a number can contain at most one decimal point, which means it is equivalent to (123.).__str__() .





For linguistic lawyers

This section contains the lexical definition of the corresponding literals.

Lexical Analysis - 2.4.5 Floating-Point Literals

 floatnumber ::= pointfloat | exponentfloat pointfloat ::= [intpart] fraction | intpart "." exponentfloat ::= (intpart | pointfloat) exponent intpart ::= digit+ fraction ::= "." digit+ exponent ::= ("e" | "E") ["+" | "-"] digit+ 

Lexical Analysis - 2.4.4 Integer Literals

 integer ::= decimalinteger | octinteger | hexinteger | bininteger decimalinteger ::= nonzerodigit digit* | "0"+ nonzerodigit ::= "1"..."9" digit ::= "0"..."9" octinteger ::= "0" ("o" | "O") octdigit+ hexinteger ::= "0" ("x" | "X") hexdigit+ bininteger ::= "0" ("b" | "B") bindigit+ octdigit ::= "0"..."7" hexdigit ::= digit | "a"..."f" | "A"..."F" bindigit ::= "0" | "1" 
+45
Oct 10 '15 at 12:55
source share

You need parsers:

 (4).__str__() 

The problem is that the lexer considers "4." will be a floating point number.

In addition, this works:

 x = 4 x.__str__() 
+86
Jun 08 2018-12-12T00:
source share

Add a space after 4 :

 4 .__str__() 

Otherwise, the lexer will divide this expression into tokens "4." , "__str__" , "(" and ")" , i.e. the first token will be interpreted as a floating point number. The lexer is always trying to build the maximum possible token.

+40
Jun 08 2018-12-12T00:
source share

actually (to increase unreadability ...):

 4..hex() 

also. it gives '0x1.0000000000000p+2' - but then it is floating, of course ...

+6
Jun 08 2018-12-12T00:
source share



All Articles