Ostatnio natknąłem się na składnię, której nigdy wcześniej nie widziałem, kiedy nauczyłem się języka Python, ani w większości samouczków. ..
Notacja wygląda tak:
f = 1..__truediv__ # or 1..__div__ for python 2
print(f(8)) # prints 0.125
Uznałem, że jest dokładnie taki sam jak (z tym, że jest oczywiście dłuższy):
f = lambda x: (1).__truediv__(x)
print(f(8)) # prints 0.125 or 1//8
Ale moje pytania to:
- Jak to zrobić?
- Co to właściwie oznacza dwie kropki?
- Jak możesz użyć tego w bardziej złożonym zestawieniu (jeśli to możliwe)?
To prawdopodobnie uratuje mi wiele linii kodu w przyszłości ... :)
(1).__truediv__
tak naprawdę nie jest tym samym1..__truediv__
, co poprzednie wywołania,int.__truediv__
podczas gdy drugiefloat.__truediv__
. Możesz też użyć1 .__truediv__
(ze spacją) `1//8
to0
nie0.125
w jednej wersji Pythona.if (x <- 3) {...}
Odpowiedzi:
To, co masz, to
float
literał bez końcowego zera, do którego następnie uzyskujesz dostęp do__truediv__
metody. Sam w sobie nie jest operatorem; pierwsza kropka jest częścią wartości zmiennoprzecinkowej, a druga to operator kropki, który ma dostęp do właściwości i metod obiektów.Możesz osiągnąć ten sam punkt, wykonując następujące czynności.
Inny przykład
Dodajemy tutaj 1,0 do 2,0, co oczywiście daje 3.0.
źródło
1..toString()
Odpowiedź na pytanie jest już wystarczająca (tj. Odpowiedź @ Paula Rooneya ), ale można również zweryfikować poprawność tych odpowiedzi.
Pozwól, że podsumuję istniejące odpowiedzi: To
..
nie jest pojedynczy element składniowy!Możesz sprawdzić, w jaki sposób kod źródłowy jest „tokenizowany” . Te tokeny przedstawiają sposób interpretacji kodu:
Więc ciąg
1.
interpretowany jest jako liczba, drugim.
jest OP (operator, w tym przypadku operator „get atrybut”), a__truediv__
nazwa metody. To tylko dostęp do__truediv__
metody float1.0
.Innym sposobem przeglądania wygenerowanego kodu bajtowego jest jego złożenie . To faktycznie pokazuje instrukcje, które są wykonywane, gdy wykonywany jest jakiś kod:
dis
Co w zasadzie mówi to samo. Ładuje atrybut
__truediv__
stałej1.0
.Jeśli chodzi o twoje pytanie
Chociaż jest to możliwe, nigdy nie powinieneś pisać takiego kodu, po prostu dlatego, że nie jest jasne, co robi kod. Dlatego nie używaj go w bardziej złożonych instrukcjach. Posunąłbym się nawet tak daleko, że nie powinieneś używać go w tak „prostych” instrukcjach, przynajmniej powinieneś użyć nawiasu do rozdzielenia instrukcji:
byłoby to zdecydowanie bardziej czytelne - ale coś w stylu:
byłoby jeszcze lepiej!
Podejście wykorzystujące
partial
zachowuje również model danych Pythona (1..__truediv__
podejście nie!), Co można zademonstrować za pomocą tego małego fragmentu:Wynika to z tego, że
1. / (1+2j)
nie jest analizowane przez,float.__truediv__
ale zcomplex.__rtruediv__
-operator.truediv
upewnia się, że operacja odwrotna jest wywoływana, gdy powróci normalna operacja,NotImplemented
ale nie wystąpią te awarie, gdy operujesz__truediv__
bezpośrednio. Ta utrata „oczekiwanego zachowania” jest głównym powodem, dla którego (zwykle) nie powinieneś bezpośrednio używać magicznych metod.źródło
Dwie kropki razem mogą początkowo być trochę niezręczne:
Ale to jest tak samo jak pisanie:
Ponieważ
float
literały można pisać w trzech formach:źródło
1.__truediv__
tak nie jest?.
Wydaje się być analizowane jako część numeru, a następnie.
na metodzie akcesor brakuje.f
jest specjalną metodą związaną na liczbach zmiennoprzecinkowych o wartości jeden. Konkretnie,w Python 3 wywołuje:
Dowód:
i:
Jeśli zrobimy:
Zachowujemy nazwę powiązaną z tą powiązaną metodą
Gdybyśmy robili to kropkowane wyszukiwanie w ciasnej pętli, mogłoby to zaoszczędzić trochę czasu.
Analiza składni abstrakcyjnego drzewa składni (AST)
Widzimy, że parsowanie wartości AST dla wyrażenia mówi nam, że otrzymujemy
__truediv__
atrybut liczby zmiennoprzecinkowej1.0
:Możesz uzyskać tę samą funkcję wynikową z:
Lub
Odliczenie
Możemy się też tam dostać przez odliczenie.
Zbudujmy to.
1 sam w sobie jest
int
:1 z kropką po nim jest liczbą zmiennoprzecinkową:
Następna kropka sama w sobie byłaby błędem SyntaxError, ale zaczyna kropkowane wyszukiwanie w instancji float:
Nikt inny o tym nie wspominał - jest to teraz „metoda związana” na float
1.0
:Tę samą funkcję moglibyśmy wykonać znacznie bardziej czytelnie:
Występ
Minusem tej
divide_one_by
funkcji jest to, że wymaga ona innej ramki stosu Pythona, co czyni ją nieco wolniejszą niż metoda związana:Oczywiście, jeśli możesz po prostu używać zwykłych literałów, jest to jeszcze szybsze:
źródło