Frage

Was ich versuche zu erreichen ist so etwas wie folgt aus:

class object:
    def __init__(self):
        WidthVariable(self)

        print self.width
        #Imagine I did this 60frames/1second later
        print self.width

#output:
>>0
>>25

Was ich will, geschieht (wie oben): Wenn WidthVariable - eine Klasse - erstellt wird, fügt die Variable width auf das Objekt Beispiel: . Diese Variable verhält sich wie eine normale Eigenschaft, aber in diesem speziellen Fall ist es schreibgeschützt ist (nur die fget Variable gesetzt ist). Darüber hinaus ruft die fget eine Funktion in WidthVariable definiert, was width zurückzukehren entscheidet.

Allerdings habe ich keine Ahnung, wie dies zu tun! Ich versuchte es normal Eigenschaften verwenden, aber ich fand, dass sie nur auf Klassen arbeiten und nicht pro Instanz - Bitte beachten Sie, dass der Code, den ich verwenden soll im __init__ von WidthVariable den oben (dh nur Code wie möglich ähnlich sein soll, den width Variable gesetzt, nirgendwo sonst). Auch self.width kann nicht funktionieren, weil ich nicht das tun, was es wie self.width() zu nennen, ich will self.width (weil es mit dem Rest des Designs hält ich habe).

Um zu klären, der vollständige Code würde wie folgt sein:

class MyObject:
    def __init__(self)
        WidthVariable(self)
        print self.width

class WidthVariable:
    def __init__(self, object)
        object.width = property(self.get_width)

    def get_width(self):
        value = #do_stuff
        return value #The Value

#output:
>>25 #Whatever the Value was
War es hilfreich?

Lösung

Da, wie @ Jonathan sagt, Deskriptoren (einschließlich Eigenschaften) sind pro-Klasse, nicht pro Instanz, die einzige Möglichkeit, verschiedene pro Instanz Deskriptoren zu bekommen, ist jede Instanz zu haben, seine eigene Klasse individualisieren. Das ist ziemlich flach und leicht, so weit wie metaprogramming geht; -) ...:

class Individualistic(object_or_whatever_bases):
  def __init__(self, whatever_args):
    self.__class__ = type('GottaBeMe', (self.__class__, object), {})
    # keep rocking...!-)

Ich füge auch object ausdrücklich, weil es gebraucht wird (in Python 2.*, und Sie tun sagen, das ist, was Sie verwenden !!!) Klassen zu machen Neuart. Verwenden Sie niemals Legacy-Klassen mehr, sie verhalten sich nicht korrekt in Bezug auf Eigenschaften und vieles andere (und für die Abwärtskompatibilität können sie nicht - in Python 3, Legacy-Klassen schließlich vernichtet worden, so dass jede Klasse ist neu Stil ohne die Forderung ausdrücklich von Objekt erbt mehr!).

Nun, jeder Beschreiber, die nur in self.__class__.__dict__ gesetzt wird beeinflussen diese eine Instanz, keine andere. Es ist ein wenig Overhead (jede GottaBeMe Klasse und damit jede Instanz hat seinen eigenen __dict__, usw.), aber nichts zu schrecklich.

Nun, alles, was gebraucht die ursprüngliche Anforderung zu erfüllen, ist zu ändern:

class WidthVariable:
    def __init__(self, object)
        object.width = property(self.get_width)

(Umbenennung auch die object arg vernünftig mit Füßen treten zu vermeiden, ein eingebauter, und macht die Klasse im neuen Stil, weil man immer jede Klasse im neuen Stil machen sollte ;-), zu:

class WidthVariable(object):
    def __init__(self, obj)
        obj.__class__.width = property(self.get_width)

Nichts zu schwarz-magicky, wie Sie sehen können! -)

Andere Tipps

Ich verstehe nicht, wie Sie Ihr Beispiel aufgebaut hat, noch verstehe ich, was Sie meinen über „normale Eigenschaften“ nur arbeiten „auf Klassen“. Hier ist, wie Sie eine schreibgeschützte Eigenschaft erstellen:

class Foo(object):
    # create read-only property "rop"
    rop = property(lambda self: self._x)

    def __init__(self):
        self._x = 0

    def tick(self):
        self._x += 1    

f = Foo()
print f.rop # prints 0
f.tick()
f.tick()
print f.rop # prints 2
f.rop = 4 # this will raise AtributeError

Ich glaube, ich jetzt verstehe Ihre Frage, und ich glaube, auch du bist kein Glück .

  

Für neuen Stil Klassen, impliziter   Anrufungen spezieller Methoden sind   nur garantiert richtig arbeiten, wenn   definiert auf den Typ eines Objekts, nicht in   die Instanz Wörterbuch des Objekts.

Descriptors (die Eigenschaften zu implementieren werden verwendet, um) in der erscheinen Klasse __dict__ und kann nicht erscheinen in der Instanz __dict__. Mit anderen Worten, ist Python Ruby nicht!

ich glücklich erwarten Korrektur von einem gottesfürchtigen Python metaprogrammer, aber ich glaube, ich bin recht.

Nicht ganz klar, was Sie wollen? aber ich nehme an, Sie wollen obj.width für jede Instanz angepasst werden Hier ist eine einfache Möglichkeit, durch Verwendung von Klar Eigenschaften, Breite Eigenschaft gibt Wert durch eine Instanz pro Rückruf zurückgegeben

class MyClass(object):
    def __init__(self, callback):
        self.callback = callback

    def get_width(self):
        return self.callback()

    width = property(get_width)

def w1(): return 0
def w2(): return 25

o1 = MyClass(w1)
o2 = MyClass(w2)

print o1.width
print o2.width

Wenn Rückruf nicht übergeben werden, können wir es WidthVariable zuweisen können, die Breite liefert basierend auf Instanz

class MyClass(object):
    def __init__(self):
        self.callback = WidthVariable(self)

    def get_width(self):
        return self.callback()

    width = property(get_width)

class WidthVariable(object):
    def __init__(self, obj):
        self.obj = obj

    def __call__(self):
        return hash(self.obj)

o1 = MyClass()
o2 = MyClass()

print o1.width
print o2.width
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top