Recent am dat peste o sintaxă n-am văzut-o când am aflat python, nici in cele mai multe tutoriale, ..
notație, se pare ceva de genul:
f = 1..__truediv__ # or 1..__div__ for python 2
print(f(8)) # prints 0.125
M-am gândit că a fost exact la fel ca (cu excepția it's mai mult, desigur):
f = lambda x: (1).__truediv__(x)
print(f(8)) # prints 0.125 or 1//8
Dar intrebarile mele sunt:
Acest lucru va salva, probabil, multe linii de cod în viitor...:)
Ceea ce ai este un "float" literal fără sfârșit zero, care apoi accesa `truediv metoda lui. L's nu un operator în sine; primul punct este parte a platformei de valoare, iar cel de-al doilea este operatorul punct de acces la obiecte, proprietăți și metode.
Puteți ajunge în același punct de a face următoarele.
>>> f = 1.
>>> f
1.0
>>> f.__floordiv__
<method-wrapper '__floordiv__' of float object at 0x7f9fb4dc1a20>
Un alt exemplu
>>> 1..__add__(2.)
3.0
Aici vom adăuga 1.0 la 2.0, care, evident, randamentele 3.0.
Întrebarea este deja suficient de răspuns (de exemplu @Paul Rooneye de răspuns) dar's, de asemenea, posibil să se verifice corectitudinea acestor răspunsuri.
Permiteți-mi să recapitulez existente răspunde: ..
nu este un singur element de sintaxă!
Puteți verifica modul în care codul sursă este "tokenized". Aceste simboluri reprezintă modul în care codul este interpretat:
>>> 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__'),
...]
Deci șirul 1.
este interpretat ca număr, cel de-al doilea .
este o OP (operator, în acest caz, "ia atribut" operator) și __truediv__
este numele metodei. Deci, aceasta este doar accesarea __truediv__ metoda de float
1.0`.
Un alt mod de vizualizare a generat bytecode este de a `dis'assemble. Acest fapt arată instrucțiunile care sunt efectuate, atunci când un cod este executat:
>>> 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
Care spune în esență același. Se încarcă atributul __truediv__
constant 1.0
.
Referitor la întrebarea ta
Și cum o poți folosi într-un mod mai complex declarație (dacă este posibil)?
Chiar dacă l's posibil niciodată nu ar trebui să scrie cod de genul asta, pur și simplu pentru că's neclar ce cod este de a face. Deci, vă rog, don't folosi în cele mai complexe situații. Aș merge chiar atât de departe încât nu ar trebui't-l folosească în așa "simplu" declarații, cel puțin, ar trebui să utilizați paranteze pentru a separa instrucțiuni:
f = (1.).__truediv__
acest lucru ar fi cu siguranță mai ușor de citit - dar ceva de-a lungul liniilor de:
from functools import partial
from operator import truediv
f = partial(truediv, 1.0)
ar fi chiar mai bine!
Abordarea folosind "parțial" păstrează, de asemenea, python's model de date (1..__truediv__
abordare nu!) care poate fi demonstrat prin acest mic fragment:
>>> 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
Acest lucru este pentru că 1. / (1+2j)
nu este evaluată de către float.__truediv__
dar cu complexe.rtruediv-
operator.truediv face sigur operația inversă se numește atunci când funcționarea normală a se întoarce Plementat
dar nu't au aceste fallbacks atunci când operatruediv` direct. Această pierdere de "comportamentului așteptat" este motivul principal pentru care (în mod normal) ar trebui't folosi magia metode direct.
Două puncte împreună, poate fi un pic ciudat la inceput:
f = 1..__truediv__ # or 1..__div__ for python 2
Dar este la fel ca scrierea:
f = 1.0.__truediv__ # or 1.0.__div__ for python 2
Pentru că "float" literale poate fi scris în trei forme:
normal_float = 1.0
short_float = 1. # == 1.0
prefixed_float = .1 # == 0.1
Ce e
f = 1..__truediv__
?
"f" este un legat metodă specială pe un flotor cu o valoare de unul. În mod special,
1.0 / x
în Python 3, invocă:
(1.0).__truediv__(x)
Dovezi:
class Float(float):
def __truediv__(self, other):
print('__truediv__ called')
return super(Float, self).__truediv__(other)
și:
>>> one = Float(1)
>>> one/2
__truediv__ called
0.5
Dacă facem:
f = one.__truediv__
Am păstra un nume legat de faptul că legat metoda
>>> f(2)
__truediv__ called
0.5
>>> f(3)
__truediv__ called
0.3333333333333333
Dacă am face asta punctate de căutare într-o buclă strânsă, acest lucru ar putea salva un pic de timp.
Putem vedea că parsarea AST pentru expresie ne spune că suntem obtinerea __truediv__
atribut pe număr în virgulă mobilă, 1.0
:
>>> import ast
>>> ast.dump(ast.parse('1..__truediv__').body[0])
"Expr(value=Attribute(value=Num(n=1.0), attr='__truediv__', ctx=Load()))"
Ai putea obține același rezultat funcție de:
f = float(1).__truediv__
Sau
f = (1.0).__truediv__
Putem obține, de asemenea, acolo de deducere.
Las's a construi.
1 de la sine este o int
:
>>> 1
1
>>> type(1)
<type 'int'>
1, cu o perioada de după este un float:
>>> 1.
1.0
>>> type(1.)
<type 'float'>
Următorul punct de sine ar fi un SyntaxError, dar începe o punctate de căutare pe instanță de float:
>>> 1..__truediv__
<method-wrapper '__truediv__' of float object at 0x0D1C7BF0>
Nimeni nu a menționat acest lucru - Acest lucru este acum un "legat metoda" pe float, 1.0
:
>>> f = 1..__truediv__
>>> f
<method-wrapper '__truediv__' of float object at 0x127F3CD8>
>>> f(2)
0.5
>>> f(3)
0.33333333333333331
Am putea realiza aceeași funcție mult mai mult readably:
>>> def divide_one_by(x):
... return 1.0/x
...
>>> divide_one_by(2)
0.5
>>> divide_one_by(3)
0.33333333333333331
Dezavantaj al `divide_one_by funcția este că necesită un alt Piton cadru stivă, ceea ce face oarecum mai lent decât cel legat de metoda:
>>> 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]
Desigur, dacă puteți folosi doar simplu literali, care's chiar mai repede:
>>> def f_3():
... for x in range(1, 11):
... 1.0/x
...
>>> timeit.repeat(f_3)
[2.1224895628296281, 2.1219930218637728, 2.1280188256941983]