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.
Ich bin ein Python-Anfänger (nicht der Anfänger-Programmierer) und ich bin mir nicht sicher, ob "Wenn Sie einen Aufruf der integrierten Len sehen, sind Sie sicher, dass das Programm danach fortgesetzt wird, anstatt eine Ausnahme auszulösen". Ich habe es versucht: 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?
Darek Nędza
4
@ DarekNędza Dies hat nichts mit dem oben Gesagten zu tun, bei dem es um eingebaute Len geht. Sie haben gerade Ihre len-Funktion definiert, die natürlich alles zurückgeben kann, was Sie wollen. OP sprach von Builtin Len, das eine __len__spezielle Methode (keine Funktion) für das betrachtete Objekt aufruft .
Veky
@Veky Wie kann ich sicher sein, dass ich eine integrierte Funktion aufrufe, 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.
Darek Nędza
3
Alex sagte ausdrücklich, wenn Sie Builtin anrufen, dann sind Sie sicher ..._. Er sagte nichts darüber, sicher zu sein, dass Sie Builtin anrufen. Aber wenn Sie das wissen wollen, können Sie : len in vars(__builtins__).values().
Veky
1
Leider ist dies ein weiteres Beispiel für das Fehlen einer gemeinsamen Basisklasse für Objekte in Python. Syntaktische Kontextumschaltung war schon immer verrückt. In einigen Fällen ist es üblich, eine Unterstrichmethode zu verwenden, in anderen sollte man so etwas wie eine Funktion verwenden, um etwas zu tun, das vielen Objekten gemeinsam ist. Es ist auch seltsam, weil viele Objekte keine semantische Verwendung für len haben. Manchmal ist das Objektmodell eher C ++, Küche sinkend ..
uchuugaka
28
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()
Antworten:
len
ist 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, abera.len()
nicht so klar sein sollte. Als Python anfing__len__
, existierte es nicht einmal undlen
war 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.quelle
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 vonlen
vs__len__
ist es nur eine kleine Überprüfung der Integrität des eingebauten Operators, die in der fehlt magische Methode:Wenn Sie einen Aufruf des
len
integrierten 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 sehenxxx.__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 aufrufennext(foo)
, und in3.*
wird die magische Methode__next__
anstelle des "oops-ey" korrekt benanntnext
! - ).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.
quelle
def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))
und es wurdeI am string
zweimal gedruckt . Kannst du es mehr erklären?__len__
spezielle Methode (keine Funktion) für das betrachtete Objekt aufruft .len
nicht 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
Ein Vorteil ist, dass Sie damit Dinge wie schreiben können
anstatt
oder
Es gibt jedoch ein etwas anderes Verhalten. Zum Beispiel bei Ints
quelle
operator.methodcaller
stattoperator.attrgetter
.Sie können Pythond-Dokumente überprüfen :
quelle