Decimal (i.e. non-prefixed) integers in Python seem to have fewer features than prefixed integers.
If I do 1.real
I get a SyntaxError: invalid decimal literal
. However, if I do 0x1.real
, then I get no error and 1
is the result. (Same for 0b1.real
and 0o1.real
, though in Python2 01.real
gives a syntax error as).
It's because the 1.
lead-in is being treated as a floating-point literal and r
is not a valid decimal digit.
Hex literals, of the form you show, are integers, so are not ambiguous in being treated as a possible floating point (there is no 0x1.1
).
If you use (1).real
to specify that the literal is just the 1
, it works fine.
The following (annotated) transcript may help:
>>> 0x1.real # Can only be integer, so works as expected.
1
>>> 1.real # Treated as floating point, "r" is invalid,
File "<stdin>", line 1
1.real
^
SyntaxError: invalid syntax
>>> (1).real # Explicitly remove ambiguity, works.
1
>>> 0x1.1 # No float hex literal in this form.
File "<stdin>", line 1
0x1.1
^
SyntaxError: invalid syntax
For completeness, the lexical tokens for numerics (integral and float) can be found in the Python docs:
integer ::= decinteger | bininteger | octinteger | hexinteger
decinteger ::= nonzerodigit (["_"] digit)* | "0"+ (["_"] "0")*
bininteger ::= "0" ("b" | "B") (["_"] bindigit)+
octinteger ::= "0" ("o" | "O") (["_"] octdigit)+
hexinteger ::= "0" ("x" | "X") (["_"] hexdigit)+
nonzerodigit ::= "1"..."9"
digit ::= "0"..."9"
bindigit ::= "0" | "1"
octdigit ::= "0"..."7"
hexdigit ::= digit | "a"..."f" | "A"..."F"
floatnumber ::= pointfloat | exponentfloat
pointfloat ::= [digitpart] fraction | digitpart "."
exponentfloat ::= (digitpart | pointfloat) exponent
digitpart ::= digit (["_"] digit)*
fraction ::= "." digitpart
exponent ::= ("e" | "E") ["+" | "-"] digitpart
You can see there that the floats do not allow for hexadecimal prefixes, which is why it can safely assume the .
in 0x1.real
is not part of the literal value.
That's not the case for 1.real
, it assumes that the .
is preceding a fractional part of a float.
A clever-enough lexer could, of course, detect an invalid decimal digit immediately after the .
and therefore assume it's a method to call on an integer. But that introduces complexity and may have other problematic edge cases.