Frage

Ich bin es gewohnt, dass Python einige nette Tricks ermöglicht, die Funktionalität an andere Objekte zu delegieren. Ein Beispiel ist die Delegation an enthaltene Objekte.

Aber es Nähte, dass ich kein Glück habe, wenn ich __ incontaint __:

class A(object):
    def __init__(self):
       self.mydict = {}
       self.__contains__ = self.mydict.__contains__

a = A()
1 in a

Ich bekomme:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: argument of type 'A' is not iterable

Was mache ich falsch? Wenn ich a .__ anrufe __ (1), geht alles reibungslos. Ich habe sogar versucht, eine __iter __ -Methode in A zu definieren, um einen iterablen Aussehen zu machen, aber es hat nicht geholfen. Was fehlt mir hier?

War es hilfreich?

Lösung

Besondere Methoden wie z. __contains__ sind nur dann besonders, wenn sie in der Klasse definiert sind, nicht auf der Instanz (außer in Legacy -Klassen in Python 2, die Sie sollten nicht trotzdem verwenden).

Machen Sie also Ihre Delegation auf Klassenebene:

class A(object):
    def __init__(self):
       self.mydict = {}

    def __contains__(self, other):
       return self.mydict.__contains__(other)

Ich würde es tatsächlich lieber als letztere als buchstabieren als return other in self.mydict, Aber das ist ein kleines Problem.

Bearbeiten: Wenn und wenn "völlig dynamische Umleitung von Spezialmethoden pro Instanz (wie angebotene Klassen im alten Stil) unverzichtbar ist, ist es nicht schwierig, sie mit neuen Klassen im Stil zu implementieren: Sie benötigen nur jede Instanz, die so eigenartig ist In seine eigene Klasse eingewickelt. Zum Beispiel:

class BlackMagic(object):
    def __init__(self):
        self.mydict = {}
        self.__class__ = type(self.__class__.__name__, (self.__class__,), {})
        self.__class__.__contains__ = self.mydict.__contains__

Im Wesentlichen nach dem kleinen Stück schwarzer Magie Neuzuweisung self.__class__ zu einem neuen Klassenobjekt (das sich genau wie das vorherige verhält, aber ein leeres Diktat und keine anderen Instanzen außer diesem hat self), überall in einer Klasse im alten Stil, die Sie zuweisen würden self.__magicname__, zuweisen self.__class__.__magicname__ Stattdessen (und stellen Sie sicher, dass es sich um ein integriertes oder eingebaut ist oder staticmethod, keine normale Python -Funktion, es sei denn natürlich in einem anderen Fall, dass sie die erhalten möchten self wenn die Instanz aufgerufen wird).

Übrigens die in Bediener in einer Instanz davon BlackMagic Klasse ist Schneller, wie es passiert, als mit einer der zuvor vorgeschlagenen Lösungen - oder zumindest, damit ich mit meinem üblichen Vertrauen messen kann -mtimeit (direkt zur built-in method, Anstatt normale Suchrouten zu verfolgen, die Vererbung und Deskriptoren beinhalten, rasiert sie ein wenig von dem Overhead).

Eine Metaklas, um die zu automatisieren self.__class__-Per-Instance-Idee wäre nicht schwer zu schreiben (es könnte die schmutzige Arbeit in der erzeugten Klasse erledigen __new__ Methode und vielleicht auch alle magischen Namen so festlegen __setattr__ oder viele, viele Eigenschaften). Dies wäre jedoch nur gerechtfertigt, wenn die Notwendigkeit dieser Funktion wirklich weit verbreitet wäre (zB portiert ein riesiges alter Python 1.5.2 Projekt, das "Spezialmethoden pro Instanz" bis moderne Python, einschließlich Python 3, großzügig anwendet).

To ich empfehlen "clever" oder "schwarze Magie" -Lösungen? Nein, ich nicht: Fast ausnahmslos ist es besser, Dinge auf einfache, einfache Weise zu tun. Aber "fast" ist hier ein wichtiges Wort, und es ist schön, solche fortgeschrittenen "Haken" für die seltenen, aber nicht existierenden Situationen zu haben, in denen ihre Verwendung tatsächlich gerechtfertigt sein kann.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top