Подтвердить что ты не робот

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

Я читал, что все в python является объектом, и поэтому я начал экспериментировать с разными типами и вызывать __str__ на них — сначала я был очень взволнован, но потом я смутился.

>>> "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
  • Почему something.__str__() работает для "всего", кроме int?
  • Является 123 не объектом типа int?
4b9b3361

Ответ 1

Итак, вы думаете, что можете dance   с плавающей запятой?

123 - это такая же часть объекта, как 3.14, "проблема" лежит в грамматических правилах языка; парсер думает, что мы собираемся определить float — не int с обратным вызовом метода.

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

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

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

>>> 123 .__str__()
'123'


Причина, по которой она не работает для 123.__str__(), заключается в том, что точка, следующая за 123, интерпретируется как десятичная точка некоторой частично объявленной плавающей запятой.

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

Парсер пытается интерпретировать __str__() как последовательность цифр, но, очевидно, не работает — и мы получаем SyntaxError, в основном говорящий, что парсер наткнулся на то, чего он не ожидал.



Разработка

При просмотре 123.__str__() анализатор python может использовать либо 3 символа и интерпретировать эти 3 символа как целое число, или, он может использовать 4 символа и интерпретировать их как start с плавающей запятой.

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

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

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

Примечание

 123 .__str__() # works fine

В приведенном выше фрагменте 123  (обратите внимание на пробел) необходимо интерпретировать как целое число, поскольку число не может содержать пробелы. Это означает, что он семантически эквивалентен (123).__str__().

Примечание

 123..__str__() # works fine

Вышеупомянутое также работает, потому что число может содержать не более одной десятичной точки, что означает, что оно эквивалентно (123.).__str__().



Для юристов-языковедов

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

Лексический анализ - 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"

Ответ 2

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

(4).__str__()

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

Кроме того, это работает:

x = 4
x.__str__()

Ответ 3

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

4 .__str__()

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

Ответ 4

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

4..hex()

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