Недавно я столкнулся с синтаксисом, который никогда не видел прежде, когда я изучал python, ни в большинстве учебных пособий ..
, это выглядит примерно так:
f = 1..__truediv__ # or 1..__div__ for python 2
print(f(8)) # prints 0.125
Я подумал, что это точно так же, как (за исключением, конечно, дольше):
f = lambda x: (1).__truediv__(x)
print(f(8)) # prints 0.125 or 1//8
Но мои вопросы:
- Как это может сделать это?
- Что это на самом деле означает с двумя точками?
- Как вы можете использовать его в более сложном утверждении (если это возможно)?
Это, вероятно, сэкономит мне много строк кода в будущем ... :)
(1).__truediv__
самом деле это не то же самое1..__truediv__
, что первый вызов, вint.__truediv__
то время как последний делаетfloat.__truediv__
. Кроме того, вы также можете использовать1 .__truediv__
(с пробелом) `1//8
это0
не так0.125
в любой версии Python.if (x <- 3) {...}
Ответы:
То, что у вас есть, это
float
литерал без конечного нуля, к которому вы затем обращаетесь по__truediv__
методу. Это не оператор сам по себе; первая точка является частью значения с плавающей точкой, а вторая является оператором точки для доступа к свойствам и методам объектов.Вы можете достичь той же точки, выполнив следующие действия.
Другой пример
Здесь мы добавляем 1,0 к 2,0, что, очевидно, дает 3,0.
источник
1..toString()
На вопрос уже получен достаточный ответ (т. Е. Ответ Пола Руни ), но также можно проверить правильность этих ответов.
Позвольте мне повторить существующие ответы: Это
..
не единственный элемент синтаксиса!Вы можете проверить, как исходный код «токенизируется» . Эти токены представляют, как код интерпретируется:
Таким образом, строка
1.
интерпретируется как число, вторым.
является OP (оператор, в данном случае оператор «get attribute»), а__truediv__
это имя метода. Так что это просто доступ к__truediv__
методу поплавка1.0
.Другой способ просмотра сгенерированного байт-кода заключается в его сборке . Это фактически показывает инструкции, которые выполняются, когда выполняется некоторый код:
dis
Который в основном говорит то же самое. Загружает атрибут
__truediv__
константы1.0
.По вашему вопросу
Хотя возможно, что вы никогда не должны писать такой код просто потому, что неясно, что делает код. Поэтому, пожалуйста, не используйте его в более сложных утверждениях. Я бы даже зашел так далеко, что вы не должны использовать его в таких «простых» выражениях, по крайней мере, вы должны использовать скобки для разделения инструкций:
это было бы определенно более читабельно - но что-то вроде:
было бы еще лучше!
Подход, использующий подход,
partial
также сохраняет модель данных Python (1..__truediv__
подход не делает!), Что можно продемонстрировать с помощью этого небольшого фрагмента:Это потому, что
1. / (1+2j)
не оценивается,float.__truediv__
а сcomplex.__rtruediv__
-operator.truediv
гарантирует, что обратная операция вызывается, когда нормальная операция возвращается,NotImplemented
но у вас нет этих откатов, когда вы работаете__truediv__
напрямую. Эта потеря «ожидаемого поведения» является основной причиной, по которой вы (обычно) не должны использовать магические методы напрямую.источник
Поначалу две точки могут быть немного неловкими:
Но это так же, как писать:
Потому что
float
литералы могут быть написаны в трех формах:источник
1.__truediv__
это не так?.
, Как представляется, анализируются как часть номера, а затем.
для метода доступа отсутствуют.f
является связанным специальным методом для числа с плавающей запятой со значением один. В частности,в Python 3 вызывает:
Свидетельство:
и:
Если мы делаем:
Мы сохраняем имя, связанное с этим связанным методом
Если бы мы делали этот точечный поиск в узком цикле, это могло бы сэкономить немного времени.
Разбор абстрактного синтаксического дерева (AST)
Мы можем видеть, что анализ AST для выражения говорит нам, что мы получаем
__truediv__
атрибут по числу с плавающей запятой1.0
:Вы можете получить ту же функцию из:
Или
дедукция
Мы также можем получить там путем вычета.
Давайте построим это.
1 само по себе является
int
:1 с точкой после поплавка:
Следующая точка сама по себе будет SyntaxError, но она начинает точечный поиск в экземпляре с плавающей точкой:
Никто другой не упомянул об этом - теперь это «связанный метод» на поплавке
1.0
:Мы могли бы выполнить ту же функцию гораздо более легко:
Производительность
Недостатком
divide_one_by
функции является то, что для нее требуется еще один фрейм стека Python, что делает его несколько медленнее, чем связанный метод:Конечно, если вы можете просто использовать обычные литералы, это еще быстрее:
источник