5

I can invoke methods on numbers only when I bind them to a name:

>>> a = 5
>>> a.bit_length()
3

I can invoke methods on string literals:

>>> 'Hello World'.lower()
'hello world'

But I cannot invoke methods on numeric literals:

>>> 5.bit_length()

This raises a SyntaxError. Is there a practical reason for that, or is it historic?

Edit Just found this related question that shows workarounds (that have already been suggested here as well). I guess this also answers the main question - with simple workarounds available, there probably wasn't enough benefit to making the grammar more complex (and harder to parse) to make this work.

Community
  • 1
  • 1
Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
  • possible duplicate of [why the bracket can't be omitted in int.to\_bytes?](http://stackoverflow.com/questions/22875862/why-the-bracket-cant-be-omitted-in-int-to-bytes) – devnull Apr 10 '14 at 10:03

2 Answers2

8

The floating point numbers are parsed as per the following rules, quoting from the docs,

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

When Python sees 5., it thinks that the grammar follows [intpart] fraction | intpart "." rule. So, it picks up the next character and finds that it doesn't match the fraction rule. That is why the syntax error is thrown.

You can get around that by

5 .bit_length()

Or enclosing that in brackets like this

(5).bit_length()
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
1

Actually thefourtheye is slightly mistaken in that the reason for syntax error is not that the fraction rule is not matched.

The reason for the syntax error is that that this rule is used to parse it as a floating point:

pointfloat    ::=  [intpart] fraction | intpart "."

The number matches the second form, that has integer part followed by a . - 5. is a valid literal for floating point, and the token stream produced by 5.bit_length produces 2 tokens: 5. (that is, float 5.0) and bit_length; a floating point literal followed by a name is syntax error in python.

It is actually possible to call a float method however, with 2 dots:

>>> 5.0.hex()
'0x1.4000000000000p+2'
>>> 5..hex()
'0x1.4000000000000p+2'

To call the int method, you need to separate the 5 from . to make them parsed as separate tokens.