2012-12-31 5 views
5

Ich habe diesen Code:Implementierung __getitem__ in neuen Stil Klassen

class A: 
    def __init__(self): 
     def method(self, item): 
      print self, ": Getting item", item 
     self.__getitem__ = types.MethodType(method, self, self.__class__) 

class B(object): 
    def __init__(self): 
     def method(self, item): 
      print self, ": Getting item", item 
     self.__getitem__ = types.MethodType(method, self, self.__class__) 

Dann funktioniert das gut:

a = A() 
a[0] 

Aber dies nicht:

b = B() 
b[0] 

Typeerror erhöhen.

fand ich, dass neuer Stil Klassen magische Methoden in der Klasse __dict__ __dict__ statt Instanz suchen. Ist das richtig? Wieso ist es so? Kennen Sie einen Artikel, der die dahinter stehenden Ideen erklärt? Ich habe versucht, RTFM, aber vielleicht nicht die richtigen oder nicht, das Ding zu fangen ...

Thank you very much! Paul

+1

Ich bin neugierig: Gibt es einen Grund, warum Sie pro Instanz wollen '__getitem__' Implementierungen? Es scheint, als ob du stromaufwärts schwimmst, vielleicht gibt es einen besseren Weg, dein Ziel zu erreichen? –

+0

Ich musste einen Klassen-Proxy erstellen.Im Grunde genommen nimmt die 'ProxyBase' Klasse die Zielklasse in ihrem'__init__' und leitet dann alle Methodenaufrufe an dieses Ziel weiter (definiert'__getattr__'). Dann können Sie eine Unterklasse von 'ProxyBase' machen und (was ich erwartet habe), z.B. definiere '__getitem__'. Dann bleibt die Funktionalität des Proxy-Objekts erhalten (gut ... mit einigen Nachteilen ...), aber mit benutzerdefiniertem Verhalten des '[]' -Operators. Dies funktioniert mit normalen Methoden, aber nicht mit speziellen. –

+0

Noch ein Kommentar: Subclassing wäre das Beste, aber ich muss die vorhandene Instanz dekorieren. Nicht um einen neuen meiner Unterklasse zu erstellen. Ich denke, das ist ein häufiges Problem, das Leute, die Python schreiben, gerne lösen. Grundsätzlich: Wie fügt man einer vorhandenen Klasse Funktionalität hinzu? Beispiel: Ich möchte 'list' mit einigen Methoden dekorieren. Ich könnte Unterklasse, aber dann die "normale" "Liste" nicht haben. Ich kann eine Instanz meiner benutzerdefinierten Klasse erstellen, aber dann müssen die dict-Inhalte kopiert werden. Die Idee ist also, st zu tun. wie 'ListWrapper ([1,2,3])' ', die nur Methodenaufrufe weiterleitet und die ursprüngliche Liste wieder verwendet. –

Antwort

6

geändert Dies ist in dem Python dokumentiert Datenmodell Dokumentation: Special method lookup for new-style classes:

Für neue Stil-Klassen Implizite Aufrufe spezieller Methoden funktionieren nur dann korrekt, wenn sie für den Objekttyp und nicht für das Instanzwörterbuch des Objekts definiert sind.

und

Das Grundprinzip hinter diesem Verhalten liegen bei einer Reihe von speziellen Methoden wie __hash__() und __repr__(), die von allen Objekten implementiert werden, einschließlich dem Typ-Objekte. Wenn die implizite Lookup dieser Methoden das herkömmliche Nachschlageprozess verwendet, würden sie fehlschlagen, wenn auf dem Typ Objekt aufgerufen sich [.]

Also, weil beide hash(int)undhash(1) arbeiten müssen, sind spezielle Methoden nachgeschlagen auf der Typ anstelle der Instanz. Wenn __hash__() wurde direkt auf dem Objekt nachgeschlagen, hash(int) würde int.__hash__() übersetzt werden, und das würde scheitern, weil int.__hash__() ein ungebundenes Methode ist und erwartet, dass auf einer tatsächlichen Instanz vonint() (z.B. 1) genannt zu werden; so für hash(int) sollte type.__hash__() stattdessen genannt:

>>> hash(1) == int.__hash__(1) 
True 
>>> hash(int) == type.__hash__(int) 
True 
>>> int.__hash__() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: descriptor '__hash__' of 'int' object needs an argument 

Dies ist eine rückwärts inkompatible Änderung, so dass es gilt nur für neuen Stil Objekte.

+0

Vielen Dank für eine sehr gute Erklärung und auch für die Verknüpfung mit den Dokumenten. Ich habe diesen Teil der Dokumentation ein wenig übersprungen, weil ich de facto nur syntaktischen Suggar implementieren muss - die Fähigkeit, inst [index] 'anstelle von' inst.method (index) 'zu verwenden und den Suggar zur Laufzeit zu erstellen. Ich denke, es ist sinnlos, über "__getitem__" in der gleichen Weise nachzudenken, wie z.B. '__hash__'. Dies ist das gleiche wie für 'list' - Sie können' instance_of_list [index] 'tun, aber Sie können' list [index] 'nicht tun (was Unsinn wäre). Ich hoffe, Sie sehen meinen Punkt ... nun ja ... Inkonsequenz. –

+0

@PavelTomasko: Nein, spezielles Gehäuse * alle * Haken sind * sehr * konsistent. Nur spezielle Gehäuse, für die wir jetzt eine Verwendung haben, würden in der Zukunft zu weiteren Problemen führen, wenn beispielsweise Verwendungen für andere Hook-Implementierungen auf dem Objekt "Typ" gefunden werden. –

+0

Ok, danke. Wieder habe ich etwas gelernt. Die besten Wünsche! –

0

Spezielle Methoden werden nur nach der Klasse eines Objekts gesucht, wenn es sich um eine Klasse im neuen Stil handelt, anders als im alten Stil. Sie definieren die __getitem__-Methode für die Instanz, die keine Auswirkung auf die neue Stilklasse hat.

+0

Danke! Ich dachte, das ist der Punkt. Aber gab es einen Grund, neue Klassen zu gründen, um so zu arbeiten? Wo wird in Python-Dokumenten gesagt/erklärt? –

Verwandte Themen