15

Possible Duplicate:
accessing a python int literals methods

In Python, everything is an object.

But then again, why doesn't the following snippet work?

1.__add__(2)

However, this does work:

n = 1
n.__add__(2)

What is the difference between n and 1?

Isn't it a design failure that it doesn't work? For instance, it does work with string literals as well.

"one".__add__("two")

For comparison, it works well on other purely object oriented languages too.

Let's take a closer look at this compiling c# example:

Console.WriteLine(100.ToString());

Then again, what distinguishes Python from C# in the perspective of everything is an object?

Community
  • 1
  • 1
poitroae
  • 21,129
  • 10
  • 63
  • 81
  • 2
    It is an object you just need brackets around it `(1).__add__(2)` – jamylak Aug 19 '12 at 09:37
  • @jamylak Please explain why the brackets are required. – poitroae Aug 19 '12 at 09:38
  • 8
    @Michael because lexer gets confused thinking it's a floating point literal. – rkhayrov Aug 19 '12 at 09:40
  • Why can't the lexer recognize that after the period there is a [a-z][A-Z] and therefore interpret it as an object. I mean, that is actually a good point why variable/method names cannot start with a number! – poitroae Aug 19 '12 at 09:43
  • 8
    Michael: Try typing `1.e8` and observing what it prints, comparing it to what you think it should print. Now try `1.e+8` and `1.e-8`. I think it would be reasonable if *you* were confused by now, so I wouldn't really blame the lexer. :P – user541686 Aug 19 '12 at 09:44

2 Answers2

34

Python's parser is deliberately very simple - one of the constraints it enforces on itself is that, to figure out what a token means, it can only look one token to the right (it is an LL(1) parser).

So, it sees [number][dot], and determines that it is a floating point literal. '_' isn't a valid character to have in a floating point literal, so it gives a syntax error.

The most obvious and most common way to overcome this is to put the number in parentheses:

(1).__add__(2)

This forces it to interpret the 1 as an integer literal, and the dot as attribute access, within the limitations of the parser.

Another interesting workaround is this:

>>> 1 .__add__(2) 
3

That is, add a space before the .. It turns out that Python always allows a space there for any attribute lookup:

>>> range(4) .count(3)
1

I found this quite surprising, but it seems that Python treats . under similar rules to +, and so will allow as much space as you like around it.

lvc
  • 34,233
  • 10
  • 73
  • 98
  • 1
    Thanks for the parser insight, mentioning LL(1)! – poitroae Aug 19 '12 at 09:49
  • @lvc The extra space there is not a special case, the python lexer allows any amount of white space between most things. eg. `range ( 4 ) . count ( 3 )` also works (SO won't let me put more than one space here but it works for more) – jamylak Aug 19 '12 at 11:01
  • @jamylak I see. I've reedited my answer with that in mind. – lvc Aug 19 '12 at 12:18
  • 4
    Strictly speaking, it is the lexer that needs to decide whether the "." is part of a floating-point literal or a delimiter token. – chepner Aug 19 '12 at 13:18
10

Python interprets 1. as float so you have to add parens:

>>> (1).__add__(2)
3

or space:

>>> 1 .__add__(2)
3

If you want float value here just put 2 dots.

>>> 1..__add__(2) #float
3.0
applicative_functor
  • 4,926
  • 2
  • 23
  • 34
  • OK, I admit the 1..__add__ surprised me. I guess this is an argument against adding range literals (like Ruby), as it would complicate the parser. – nneonneo Aug 23 '12 at 06:32