Недавно я наткнулся на синтаксис я никогда не видел, когда я узнал, питона, ни в большинстве учебников, запись..
, это выглядит примерно так:
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
Но мои вопросы:
Это, вероятно, спасти меня много строк кода в будущем...:)
Что у вас есть поплавок
литерал без нуля на конце, который вы затем получить доступ к методуtruediv от. Это's не оператор сам по себе; первая точка-это часть стоимости поплавок, а второй оператор "точка" для доступа к свойствам объектов и методов.
Вы можете достичь той же точки, выполнив следующие действия.
>>> 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.
Вопрос уже достаточно ответили (т. е. @Павел Руни, Ответить с) но это's также можно проверить правильность этих ответов.
Позвольте мне резюмировать существующие ответы: ..
- это не один элемент синтаксиса!
Вы можете проверить исходный код на"разбиваются" и. Эти жетоны представляют собой, как код интерпретируется:
>>> 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.
интерпретируется как число, второй -.
- это ОП (оператор, в данном случае "и вам атрибута" и оператор) иtruediv - это имя метода. Так что это просто доступ к методуtruediv поплавка
1.0`.
Еще один способ просмотра сгенерированного байт-кода в `Дис'assemble его. Это на самом деле показывает, инструкции, которые выполняются, когда какой-то код выполняется:
>>> 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
.
Что касается вашего вопроса
И как вы можете использовать его в более сложное высказывание (если это возможно)?
Даже если это's возможно, вы никогда не должны написать код вроде этого, просто потому, что она'ы неясно, что делает код. Поэтому, пожалуйста, Дон'т использовать его в более сложных инструкций. Я бы даже пойти так далеко, что вы должны'т использовать его в так, что "простой" и заявления, по крайней мере, вы должны использовать скобки для отдельной инструкции:
f = (1.).__truediv__
это будет определенно более читабельным, но что-то вдоль линий:
from functools import partial
from operator import truediv
f = partial(truediv, 1.0)
было бы еще лучше!
Подход, используя частичный и сохраняет Пайтон'модели данных с (в `1..подход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+2Д)
не обрабатывается поплавок.__truediv__
а с комплекса.__rtruediv__
- оператор.truediv
делает, что обратная операция называется, когда нормальная работа возвращает реализованы, но вы Don'т иметь эти откаты, когда вы работаете на
truediv` напрямую. Эта потеря на "поведения" это главная причина, почему вы (обычно) стоит'т использовать магические методы напрямую.
Две точки вместе может быть немного неудобно в первую очередь:
f = 1..__truediv__ # or 1..__div__ for python 2
Но это все равно, что писать:
f = 1.0.__truediv__ # or 1.0.__div__ for python 2
Потому что поплавок
литералы можно записать в трех формах:
normal_float = 1.0
short_float = 1. # == 1.0
prefixed_float = .1 # == 0.1
что такое
Ф = 1..__truediv__
?
Ф
- это привязан специальный метод на поплавок со значением один. В частности,
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
Если мы делаем что пунктирной подстановки в непрерывном цикле, это может сэкономить немного времени.
Мы видим, что анализ на АСТ за выражение говорит нам, что мы получаем атрибутtruediv на число с плавающей запятой, 1.0
:
>>> import ast
>>> ast.dump(ast.parse('1..__truediv__').body[0])
"Expr(value=Attribute(value=Num(n=1.0), attr='__truediv__', ctx=Load()))"
Вы могли бы получить те же самые полученной функции от:
f = float(1).__truediv__
Или
f = (1.0).__truediv__
Мы также можем получить там вычет.
Позвольте'ы построить его.
1 сам по себе является инт
:
>>> 1
1
>>> type(1)
<type 'int'>
1 с периодом после его поплавка:
>>> 1.
1.0
>>> type(1.)
<type 'float'>
Следующая точка сама по себе будет синтаксис ошибка, но она начинается пунктирная поиска на экземпляре поплавка:
>>> 1..__truediv__
<method-wrapper '__truediv__' of float object at 0x0D1C7BF0>
Никто не упомянул эту - Это "и связанный метод и" на поплавок, 1.0
:
>>> f = 1..__truediv__
>>> f
<method-wrapper '__truediv__' of float object at 0x127F3CD8>
>>> f(2)
0.5
>>> f(3)
0.33333333333333331
Мы могли бы выполнить ту же функцию гораздо более читаемо:
>>> def divide_one_by(x):
... return 1.0/x
...
>>> divide_one_by(2)
0.5
>>> divide_one_by(3)
0.33333333333333331
Производительность ##
Недостатком функции divide_one_by заключается в том, что он требует еще один питон кадр стека, что делает его немного медленнее, чем соответствующий метод:
>>> def f_1():
... for x in range(1, 11):
... f(x)
...
>>> def f_2():
... for x in range(1, 11):
... divide_one_by(x)
...
>>> timeit.repeat(f_1)
[2.5495760687176485, 2.5585621018805469, 2.5411816588331888]
>>> timeit.repeat(f_2)
[3.479687248616699, 3.46196088706062, 3.473726342237768]
Конечно, если вы можете просто использовать простые литералы, что's еще быстрее:
>>> def f_3():
... for x in range(1, 11):
... 1.0/x
...
>>> timeit.repeat(f_3)
[2.1224895628296281, 2.1219930218637728, 2.1280188256941983]