Ich bin kürzlich auf eine Syntax gestoßen, die ich noch nie gesehen habe, als ich Python gelernt habe, und in den meisten Tutorials ..
sieht die Notation ungefähr so aus:
f = 1..__truediv__ # or 1..__div__ for python 2
print(f(8)) # prints 0.125
Ich dachte, es wäre genau das gleiche wie (außer es ist natürlich länger):
f = lambda x: (1).__truediv__(x)
print(f(8)) # prints 0.125 or 1//8
Aber meine Fragen sind:
- Wie kann es das machen?
- Was bedeutet das eigentlich mit den beiden Punkten?
- Wie können Sie es in einer komplexeren Anweisung verwenden (wenn möglich)?
Dies wird mir wahrscheinlich in Zukunft viele Codezeilen ersparen ... :)
(1).__truediv__
ist nicht wirklich dasselbe wie1..__truediv__
, wie der erstere anruft,int.__truediv__
während der letztere es tutfloat.__truediv__
. Alternativ können Sie auch1 .__truediv__
(mit einem Leerzeichen) `1//8
ist0
nicht0.125
, in beiden Versionen von Python.if (x <- 3) {...}
Antworten:
Was Sie haben, ist ein
float
Literal ohne die nachfolgende Null, auf das Sie dann zugreifen__truediv__
. Es ist kein Operator an sich; Der erste Punkt ist Teil des Gleitkommawerts und der zweite Punkt ist der Punktoperator für den Zugriff auf die Objekteigenschaften und -methoden.Sie können den gleichen Punkt erreichen, indem Sie die folgenden Schritte ausführen.
Ein anderes Beispiel
Hier addieren wir 1,0 zu 2,0, was offensichtlich 3,0 ergibt.
quelle
1..toString()
Die Frage ist bereits ausreichend beantwortet (dh die Antwort von @Paul Rooney ), es ist jedoch auch möglich, die Richtigkeit dieser Antworten zu überprüfen.
Lassen Sie mich die vorhandenen Antworten zusammenfassen: Das
..
ist kein einzelnes Syntaxelement!Sie können überprüfen, wie der Quellcode "tokenisiert" ist . Diese Token stellen dar, wie der Code interpretiert wird:
Die Zeichenfolge
1.
wird also als Zahl interpretiert, die zweite.
ist ein OP (ein Operator, in diesem Fall der Operator "get attribute") und__truediv__
der Methodenname. Dies ist also nur ein Zugriff auf die__truediv__
Methode des Floats1.0
.Eine andere Möglichkeit, den generierten Bytecode anzuzeigen, besteht darin , ihn zusammenzusetzen. Dies zeigt tatsächlich die Anweisungen, die ausgeführt werden, wenn Code ausgeführt wird:
dis
Was im Grunde das gleiche sagt. Es lädt das Attribut
__truediv__
der Konstante1.0
.Was Ihre Frage betrifft
Auch wenn es möglich ist, dass Sie niemals solchen Code schreiben sollten, einfach weil unklar ist, was der Code tut. Verwenden Sie es also bitte nicht in komplexeren Aussagen. Ich würde sogar so weit gehen, dass Sie es nicht in so "einfachen" Anweisungen verwenden sollten, zumindest sollten Sie die Anweisungen in Klammern trennen:
dies wäre definitiv besser lesbar - aber etwas in der Art von:
wäre noch besser!
Der verwendete Ansatz
partial
bewahrt auch das Python-Datenmodell (der1..__truediv__
Ansatz nicht!), Was durch dieses kleine Snippet demonstriert werden kann:Dies liegt daran, dass
1. / (1+2j)
nicht von,float.__truediv__
sondern mitcomplex.__rtruediv__
- ausgewertet wird , umoperator.truediv
sicherzustellen, dass die umgekehrte Operation aufgerufen wird, wenn die normale Operation zurückkehrt,NotImplemented
aber Sie diese Fallbacks nicht haben, wenn Sie__truediv__
direkt arbeiten. Dieser Verlust des "erwarteten Verhaltens" ist der Hauptgrund, warum Sie (normalerweise) magische Methoden nicht direkt anwenden sollten.quelle
Zwei Punkte zusammen können zunächst etwas umständlich sein:
Aber es ist dasselbe wie beim Schreiben:
Weil
float
Literale in drei Formen geschrieben werden können:quelle
1.__truediv__
nicht?.
scheint als Teil der Nummer analysiert zu werden, und dann.
fehlt das für den Methoden-Accessor.f
ist eine gebundene Spezialmethode für einen Float mit dem Wert Eins. Speziell,Ruft in Python 3 Folgendes auf:
Beweis:
und:
Wenn wir es tun:
Wir behalten einen Namen, der an diese gebundene Methode gebunden ist
Wenn wir diese gepunktete Suche in einer engen Schleife durchführen würden, könnte dies ein wenig Zeit sparen.
Analysieren des abstrakten Syntaxbaums (AST)
Wir können sehen, dass das Parsen des AST für den Ausdruck uns sagt, dass wir das
__truediv__
Attribut für die Gleitkommazahl erhalten1.0
:Sie könnten dieselbe resultierende Funktion erhalten von:
Oder
Abzug
Wir können auch durch Abzug dorthin gelangen.
Lass es uns aufbauen.
1 für sich ist ein
int
:1 mit einem Punkt nach dem Float:
Der nächste Punkt an sich wäre ein SyntaxError, aber es beginnt eine gepunktete Suche auf der Instanz des Floats:
Niemand sonst hat dies erwähnt - Dies ist jetzt eine "gebundene Methode" auf dem Float ,
1.0
:Wir könnten dieselbe Funktion viel besser lesbar machen:
Performance
Der Nachteil der
divide_one_by
Funktion ist, dass ein weiterer Python-Stack-Frame erforderlich ist, wodurch sie etwas langsamer als die gebundene Methode ist:Wenn Sie nur einfache Literale verwenden können, ist das natürlich noch schneller:
quelle