Ich habe in letzter Zeit mit Python herumgespielt, und eine Sache, die ich etwas seltsam finde, ist die weit verbreitete Verwendung von 'magischen Methoden', z. B. um seine Länge verfügbar zu machen, ein Objekt implementiert eine Methode def __len__(self)
, und dann wird es aufgerufen, wenn Sie schreiben len(obj)
.
Ich habe mich nur gefragt, warum Objekte eine len(self)
Methode nicht einfach definieren und sie direkt als Mitglied des Objekts aufrufen lassen, z obj.len()
. Ich bin mir sicher, dass es gute Gründe dafür geben muss, dass Python es so macht, aber als Neuling habe ich noch nicht herausgefunden, was sie sind.
python
magic-methods
Greg Beech
quelle
quelle
len()
oderreversed()
gilt für viele Arten von Objekten, aber eine Methode wieappend()
nur für Sequenzen usw.Antworten:
AFAIK
len
ist in dieser Hinsicht etwas Besonderes und hat historische Wurzeln.Hier ist ein Zitat aus den FAQ :
Die anderen "magischen Methoden" ( in der Python-Folklore eigentlich als spezielle Methode bezeichnet ) sind sehr sinnvoll, und ähnliche Funktionen gibt es auch in anderen Sprachen. Sie werden hauptsächlich für Code verwendet, der implizit aufgerufen wird, wenn eine spezielle Syntax verwendet wird.
Beispielsweise:
und so weiter...
quelle
Aus dem Zen von Python:
Dies ist einer der Gründe - mit benutzerdefinierten Methoden, Entwickler frei sein würde , eine andere Methode Namen zu wählen, wie
getLength()
,length()
,getlength()
oder was auch immer. Python erzwingt eine strikte Benennung, damit die allgemeine Funktionlen()
verwendet werden kann.Alle Operationen , die für viele Arten von Objekten gemeinsam sind , in magische Methoden setzen, wie
__nonzero__
,__len__
oder__repr__
. Sie sind jedoch meistens optional.Das Überladen von Operatoren erfolgt auch mit magischen Methoden (z. B.
__le__
), daher ist es sinnvoll, sie auch für andere gängige Operationen zu verwenden.quelle
Python verwendet das Wort "magische Methoden" , da diese Methoden wirklich Magie für Ihr Programm ausführen. Einer der größten Vorteile der Verwendung der magischen Methoden von Python besteht darin, dass sie eine einfache Möglichkeit bieten, Objekte dazu zu bringen, sich wie integrierte Typen zu verhalten. Das heißt, Sie können hässliche, kontraintuitive und nicht standardmäßige Methoden zur Ausführung grundlegender Operatoren vermeiden.
Betrachten Sie ein folgendes Beispiel:
Dies gibt einen Fehler aus, da der Wörterbuchtyp das Hinzufügen nicht unterstützt. Erweitern wir nun die Wörterbuchklasse und fügen die magische Methode "__add__" hinzu :
Jetzt gibt es folgende Ausgabe.
Durch Hinzufügen dieser Methode ist plötzlich Magie passiert und der Fehler, den Sie früher hatten, ist verschwunden.
Ich hoffe, es macht dir die Dinge klar. Weitere Informationen finden Sie unter:
Ein Leitfaden zu Pythons magischen Methoden (Rafe Kettler, 2012)
quelle
Einige dieser Funktionen können mehr als eine einzelne Methode implementieren (ohne abstrakte Methoden in einer Oberklasse). Zum Beispiel
bool()
verhält es sich so:Sie können auch 100% sicher sein, dass
bool()
immer True oder False zurückgegeben wird. Wenn Sie sich auf eine Methode verlassen würden, könnten Sie nicht ganz sicher sein, was Sie zurückbekommen würden.Einige andere Funktionen mit relativ komplizierten Implementierungen (die komplizierter sind als die zugrunde liegenden magischen Methoden) sind
iter()
undcmp()
und alle Attributmethoden (getattr
,setattr
unddelattr
). Dinge wieint
auch Zugriff auf magische Methoden, wenn Sie Zwang ausüben (Sie können implementieren__int__
), aber doppelte Pflicht als Typen.len(obj)
ist eigentlich der einzige Fall, in dem ich nicht glaube, dass es jemals anders ist alsobj.__len__()
.quelle
hasattr()
würde ichtry:
/ verwendenexcept AttributeError:
und anstelle vonif obj.__len__(): return True else: return False
würde ich nur sagen,return obj.__len__() > 0
aber das sind nur stilistische Dinge.bool(x)
Bezug genommen wirdx.__nonzero__()
) würde Ihre Methode nicht funktionieren. Bool-Instanzen haben eine Methode__nonzero__()
, und Ihr Code würde sich weiterhin selbst aufrufen, sobald obj ein Bool war. Vielleichtbool(obj.__bool__())
sollten Sie genauso behandelt werden wie Sie__len__
? (Oder funktioniert dieser Code tatsächlich für Python 3?)len(x)
undx.__len__()
besteht darin, dass ersterer OverflowError für Längen auslöst, die größer sindsys.maxsize
, während letzterer im Allgemeinen nicht für in Python implementierte Typen gilt. Dies ist jedoch eher ein Fehler als eine Funktion (z. B. kann das Bereichsobjekt von Python 3.2 meist beliebig große Bereiche verarbeiten, die Verwendunglen
mit ihnen kann jedoch fehlschlagen. Auch dies__len__
schlägt fehl, da sie eher in C als in Python implementiert sind)Sie sind nicht wirklich "magische Namen". Es ist nur die Schnittstelle, die ein Objekt implementieren muss, um einen bestimmten Dienst bereitzustellen. In diesem Sinne sind sie nicht magischer als jede vordefinierte Schnittstellendefinition, die Sie neu implementieren müssen.
quelle
Während der Grund größtenteils historisch ist, gibt es in Pythons einige Besonderheiten
len
, die die Verwendung einer Funktion anstelle einer geeigneten Methode erforderlich machen.Einige Operationen in Python sind als Methoden implementiert, zum Beispiel
list.index
unddict.append
, während andere als Callables und magische Methoden implementiert werden, zum Beispielstr
unditer
undreversed
. Die beiden Gruppen unterscheiden sich so stark, dass der unterschiedliche Ansatz gerechtfertigt ist:str
,int
Und Freunde sind Typen. Es ist sinnvoller, den Konstruktor aufzurufen.iter
aufrufen,__getitem__
wenn__iter__
es nicht verfügbar ist, und unterstützt zusätzliche Argumente, die nicht in einen Methodenaufruf passen. Aus dem gleichen Grundit.next()
wurdenext(it)
in neueren Versionen von Python geändert - es ist sinnvoller.__iter__
und__next__
- es heißt diefor
Schleife. Aus Gründen der Konsistenz ist eine Funktion besser. Und es macht es für bestimmte Optimierungen besser.repr
wiestr
sie. Mit imstr(x)
Vergleichx.repr()
wäre verwirrend.isinstance
.getattr(x, 'a')
sind eine andere Artx.a
und Weise undgetattr
teilen viele der oben genannten Eigenschaften.Ich persönlich nenne die erste Gruppe methodenähnlich und die zweite Gruppe operatorähnlich. Es ist keine sehr gute Unterscheidung, aber ich hoffe, es hilft irgendwie.
Trotzdem
len
passt es nicht genau in die zweite Gruppe. Es ist näher an den Operationen im ersten, mit dem einzigen Unterschied, dass es weitaus häufiger ist als fast alle anderen. Aber das einzige, was es tut, ist anzurufen__len__
, und es ist sehr naheL.index
. Es gibt jedoch einige Unterschiede. Zum Beispiel__len__
könnte für die Implementierung anderer Funktionen aufgerufen werden, z. B.bool
wenn die Methode aufgerufen wurdelen
, könnten Siebool(x)
mit einer benutzerdefiniertenlen
Methode brechen , die völlig andere Dinge tut.Kurz gesagt, Sie haben eine Reihe sehr häufiger Funktionen, die Klassen implementieren können, auf die über einen Operator, über eine spezielle Funktion (die normalerweise mehr als die Implementierung als Operator ausführt), während der Objektkonstruktion und auf alle zugegriffen werden kann einige gemeinsame Merkmale teilen. Der Rest ist eine Methode. Und
len
ist eine Ausnahme von dieser Regel.quelle
Zu den beiden oben genannten Beiträgen gibt es nicht viel hinzuzufügen, aber alle "magischen" Funktionen sind überhaupt nicht wirklich magisch. Sie sind Teil des Moduls __ builtins__, das beim Start des Interpreters implizit / automatisch importiert wird. Dh:
geschieht jedes Mal, bevor Ihr Programm startet.
Ich dachte immer, es wäre korrekter, wenn Python dies nur für die interaktive Shell tun würde und Skripte benötigt, um die verschiedenen Teile aus den benötigten Buildins zu importieren. Auch wahrscheinlich wäre eine andere __ main__ Handhabung in Shells nett oder interaktiv. Schauen Sie sich auf jeden Fall alle Funktionen an und sehen Sie, wie es ohne sie ist:
quelle