Что такое Python. ("точка точка") синтаксис нотации?
недавно я столкнулся с синтаксисом, который я никогда не видел раньше, когда я изучал 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
но мои вопросы:
- как он может это сделать?
- что это на самом деле означает с двумя точками?
- как вы можете использовать его в более сложное высказывание (Если возможно)?
Это, вероятно, сэкономит мне много строк кода в будущем...:)
4 ответа:
ты
float
литерал без завершающего нуля, который вы затем получаете доступ к__truediv__
метод. Это не оператор сам по себе; первая точка является частью значения float, а вторая-оператор точки для доступа к свойствам и методам объектов.вы можете достичь той же точки, выполнив следующие действия.
>>> f = 1. >>> f 1.0 >>> f.__floordiv__ <method-wrapper '__floordiv__' of float object at 0x7f9fb4dc1a20>
еще один пример
>>> 1..__add__(2.) 3.0
здесь мы добавляем 1.0 до 2.0, что, очевидно, дает 3.0.
вопрос уже достаточно ответил (т. е. @Paul Rooneys ответ), но также можно проверить правильность этих ответов.
позвольте мне повторить существующие ответы:
..
- это не один элемент синтаксиса!вы можете проверить исходный код "tokenized". Эти маркеры представляют, как интерпретируется код:
>>> from tokenize import tokenize >>> from io import BytesIO >>> s = "1..__truediv__" >>> list(tokenize(BytesIO(s.encode('utf-8')).readline)) [... TokenInfo(type=2 (NUMBER), string='1.', start=(1, 0), end=(1, 2), line='1..__truediv__'), TokenInfo(type=53 (OP), string='.', start=(1, 2), end=(1, 3), line='1..__truediv__'), TokenInfo(type=1 (NAME), string='__truediv__', start=(1, 3), end=(1, 14), line='1..__truediv__'), ...]
в строке
1.
интерпретируется как число, второй.
- это OP (оператор, в данном случае оператор "get attribute") и__truediv__
- это имя метода. Так что это просто доступ к__truediv__
метод поплавка1.0
.другой способ просмотра сгенерированного байт-кода -
dis
собрать его. Это фактически показывает инструкции, которые выполняются при выполнении некоторого кода:>>> import dis >>> def f(): ... return 1..__truediv__ >>> dis.dis(f) 4 0 LOAD_CONST 1 (1.0) 3 LOAD_ATTR 0 (__truediv__) 6 RETURN_VALUE
который в основном говорит то же самое. Он загружает атрибут
__truediv__
константы1.0
.
что касается вашего вопроса
и как вы можете использовать его в более сложное высказывание (если это возможно)?
хотя возможно, что вы никогда не должны писать такой код, просто потому, что неясно, что делает код. Поэтому, пожалуйста, не используйте его в более сложных утверждениях. Я бы даже пошел так далеко, что вы не должны использовать его в таких "простых" утверждениях, по крайней мере, вы должны использовать скобки для разделения инструкции:
f = (1.).__truediv__
это было бы определенно более читаемым - но что-то вроде:
from functools import partial from operator import truediv f = partial(truediv, 1.0)
было бы еще лучше!
подход с использованием
partial
хранит модель данных python (the1..__truediv__
подход не дает!) который может быть продемонстрирован этим небольшим фрагментом:>>> f1 = 1..__truediv__ >>> f2 = partial(truediv, 1.) >>> f2(1+2j) # reciprocal of complex number - works (0.2-0.4j) >>> f2('a') # reciprocal of string should raise an exception TypeError: unsupported operand type(s) for /: 'float' and 'str' >>> f1(1+2j) # reciprocal of complex number - works but gives an unexpected result NotImplemented >>> f1('a') # reciprocal of string should raise an exception but it doesn't NotImplemented
это так
1. / (1+2j)
не обрабатываетсяfloat.__truediv__
но сcomplex.__rtruediv__
-operator.truediv
гарантирует обратного операция вызывается, когда нормальная операция возвращаетNotImplemented
но у вас нет этих резервов, когда вы работаете на__truediv__
напрямую. Эта потеря "ожидаемого поведения" является основной причиной, по которой вы (обычно) не должны использовать магические методы напрямую.
две точки вместе может быть немного неудобно в первую очередь:
f = 1..__truediv__ # or 1..__div__ for python 2
но это то же самое, что писать:
f = 1.0.__truediv__ # or 1.0.__div__ for python 2
, потому что
float
литералы могут быть записаны в трех формах:normal_float = 1.0 short_float = 1. # == 1.0 prefixed_float = .1 # == 0.1
что это
f = 1..__truediv__
?
f
- это связанный специальный метод на поплавке со значением единицы. В частности,1.0 / x
в Python 3, вызывает:
(1.0).__truediv__(x)
доказательства:
class Float(float): def __truediv__(self, other): print('__truediv__ called') return super(Float, self).__truediv__(other)
и:
>>> one = Float(1) >>> one/2 __truediv__ called 0.5
если мы это сделаем:
f = one.__truediv__
мы сохраняем имя, привязанное к этому связанному методу
>>> f(2) __truediv__ called 0.5 >>> f(3) __truediv__ called 0.3333333333333333
если бы мы делали этот точечный поиск в узком цикле, это могло бы немного сэкономить время.
разбор абстрактного синтаксического дерева (AST)
мы видим, что разбор AST для выражения говорит нам, что мы получаем