Gibt es einen Unterschied zwischen Anrufen len([1,2,3])oder [1,2,3].__len__()?
Wenn es keinen sichtbaren Unterschied gibt, was wird hinter den Kulissen anders gemacht?
Gibt es einen Unterschied zwischen Anrufen len([1,2,3])oder [1,2,3].__len__()?
Wenn es keinen sichtbaren Unterschied gibt, was wird hinter den Kulissen anders gemacht?
Antworten:
lenist eine Funktion zum Abrufen der Länge einer Sammlung. Es funktioniert durch Aufrufen der __len__Methode eines Objekts . __something__Attribute sind speziell und in der Regel mehr als man denkt und sollten im Allgemeinen nicht direkt aufgerufen werden.
Es wurde vor langer Zeit entschieden, dass die Länge eines Objekts eine Funktion und kein Methodencode sein sollte, da len(a)die Bedeutung für Anfänger klar, aber a.len()nicht so klar sein sollte. Als Python anfing __len__, existierte es nicht einmal und lenwar eine besondere Sache, die mit einigen Arten von Objekten funktionierte. Ob die Situation, die uns dies hinterlässt, absolut sinnvoll ist oder nicht, es ist hier, um zu bleiben.
Es ist häufig der Fall, dass das "typische" Verhalten eines integrierten Operators oder Operators darin besteht, (mit unterschiedlicher und besserer Syntax) geeignete magische Methoden (solche mit Namen wie __whatever__) für die beteiligten Objekte aufzurufen. Oft hat der eingebaute oder Operator einen "Mehrwert" (er kann je nach den beteiligten Objekten unterschiedliche Pfade einschlagen) - im Fall von lenvs __len__ist es nur eine kleine Überprüfung der Integrität des eingebauten Operators, die in der fehlt magische Methode:
>>> class bah(object):
... def __len__(self): return "an inch"
...
>>> bah().__len__()
'an inch'
>>> len(bah())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object cannot be interpreted as an integer
Wenn Sie einen Aufruf des lenintegrierten Geräts sehen , sind Sie sicher, dass der Aufruf eine Ganzzahl, nicht negativ und weniger als 2 ** 31 zurückgegeben hat, wenn das Programm danach fortgesetzt wird, anstatt eine Ausnahme auszulösen Wenn Sie einen Anruf bei sehen xxx.__len__(), haben Sie keine Gewissheit (außer dass der Autor des Codes entweder nicht mit Python vertraut ist oder bis zu nichts Gutes tut ;-).
Andere integrierte Funktionen bieten einen noch höheren Mehrwert als einfache Überprüfungen und Lesbarkeit. Durch die einheitliche Gestaltung von Python für die Arbeit über Aufrufe von integrierten Funktionen und die Verwendung von Operatoren, niemals durch Aufrufe von magischen Methoden, wird den Programmierern die Last erspart, sich daran zu erinnern, welcher Fall welcher ist. (Manchmal tritt ein Fehler auf: Bis 2.5 mussten Sie aufrufen foo.next()- in 2.6, während dies aus Gründen der Abwärtskompatibilität immer noch funktioniert, sollten Sie aufrufen next(foo), und in 3.*wird die magische Methode __next__anstelle des "oops-ey" korrekt benannt next! - ).
Die allgemeine Regel sollte daher sein, eine magische Methode niemals direkt (aber immer indirekt über eine integrierte Methode) aufzurufen, es sei denn, Sie wissen genau, warum Sie dies tun müssen (z. B. wenn Sie eine solche Methode in einer Unterklasse überschreiben, wenn die Die Unterklasse muss sich auf die Oberklasse verschieben, die durch expliziten Aufruf der magischen Methode erfolgen muss.
def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))und es wurde I am stringzweimal gedruckt . Kannst du es mehr erklären?
__len__spezielle Methode (keine Funktion) für das betrachtete Objekt aufruft .
lennicht eine andere Funktion (wie in meinem Beispiel), die zufällig denselben Namen hat - len. Es gibt keine Warnung wie "Sie definieren die integrierte Funktion len neu" oder ähnliches. Meiner Meinung nach kann ich nicht sicher sein, was Alex in seiner Antwort angegeben hat.
len in vars(__builtins__).values().
Sie können sich len () als ungefähr gleichwertig mit vorstellen
def len(x):
return x.__len__()
Ein Vorteil ist, dass Sie damit Dinge wie schreiben können
somelist = [[1], [2, 3], [4, 5, 6]]
map(len, somelist)
anstatt
map(list.__len__, somelist)
oder
map(operator.methodcaller('__len__'), somelist)
Es gibt jedoch ein etwas anderes Verhalten. Zum Beispiel bei Ints
>>> (1).__len__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute '__len__'
>>> len(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'int' has no len()
operator.methodcallerstatt operator.attrgetter.
Sie können Pythond-Dokumente überprüfen :
>>> class Meta(type):
... def __getattribute__(*args):
... print "Metaclass getattribute invoked"
... return type.__getattribute__(*args)
...
>>> class C(object):
... __metaclass__ = Meta
... def __len__(self):
... return 10
... def __getattribute__(*args):
... print "Class getattribute invoked"
... return object.__getattribute__(*args)
...
>>> c = C()
>>> c.__len__() # Explicit lookup via instance
Class getattribute invoked
10
>>> type(c).__len__(c) # Explicit lookup via type
Metaclass getattribute invoked
10
>>> len(c) # Implicit lookup
10