Доступ к атрибутам литералов работает для всех типов, но не для `int`; Зачем? [Дубликат]

This question already has an answer here:

Why is “1.real” a syntax error but “1 .real” valid in Python? 3 answers

Я прочитал, что все в Python является объектом, и поэтому я начал экспериментировать с различными типами и вызывая__str__ на них & # x2014; Сначала я чувствовал себя очень взволнованным, но потом я запутался.

>>> "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" besides int? Is 123 not an object of type int?
 Filip Roséen - refp11 окт. 2015 г., 16:41
@Rusian два разных вопроса, с ответами самостоятельно, были объединены; вот почему временные метки выглядят немного странно.
 Marc van Leeuwen11 окт. 2015 г., 14:03
Посмотрите, что говорится в сообщении:invalid syntax, Это указывает на то, что это не имеет никакого отношения к значению конструкции, просто к тому, как вы ее записали.

Ответы на вопрос(4)

Вам нужны парены:

(4).__str__()

Проблема в том, что лексер думает "4." будет число с плавающей запятой.

Также это работает:

x = 4
x.__str__()

собственно (для увеличения нечитаемости ...):

4..hex()

тоже верно это дает'0x1.0000000000000p+2' - но тогда это поплавок, конечно ...

Решение Вопроса
So you think you can  dance  floating-point?

123 такой же объект, как3.14«проблема» лежит в грамматических правилах языка; парсер думает, что мы собираемся определитьfloat & # X2014; неint с завершающим вызовом метода.

Мы получим ожидаемое поведение, если заключить число в круглые скобки, как показано ниже.

>>> <b>(123).__str__()</b>
'123'

Или если мы просто добавим пробел после123:

>>> <b>123 .__str__()</b>
'123'


Причина, по которой это не работает123.__str__() это то, чтоdot следуя123 интерпретируется какdecimal-point некоторые частично объявленыfloating-point.

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

Парсер пытается интерпретировать__str__() в виде последовательности цифр, но, очевидно, не удается & # x2014; и мы получаемSyntaxError в основном говоря, что синтаксический анализатор наткнулся на то, чего он не ожидал.


Elaboration

При взгляде на123.__str__() парсер python может использовать либо3 символы и интерпретировать эти3 персонажи какinteger, or это может использовать4 символы и интерпретировать их какstart изfloating-point.

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

Точно так же, как маленький ребенок хочет, чтобы на тарелке было как можно больше пирога, парсер жаден и хотел бы проглотить столько, сколько он может одновременно & # x2014; даже если это не всегда лучшая из идей, в качестве таковой выбрана последняя («лучшая») альтернатива.

Когда это позже поймет, что__str__() никоим образом не может быть истолковано какdecimals изfloating-point уже слишком поздно;SyntaxError.

Note

 123 .__str__() # works fine

In the above snippet, 123  (note the space) must be interpreted as an integer since no number can 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, meaning that it is equivalent to (123.).__str__().


For the language-lawyers

Этот раздел содержит лексическое определение соответствующих литералов.

Лексический анализ - 2.4.5 Литералы с плавающей точкой

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

Лексический анализ - 2.4.4 Целочисленные литералы

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"

Добавьте пробел после4:

4 .__str__()

В противном случае лексер разделит это выражение на токены."4.", "__str__", "(" а также")"первый токен интерпретируется как число с плавающей запятой. Лексер всегда пытается собрать максимально длинный токен.

Ваш ответ на вопрос