Question

Ce que j'essaie de réaliser ressemble à ceci:

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

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

#output:
>>0
>>25

Ce que je souhaite (comme ci-dessus): lorsque WidthVariable - une classe - est créée, il ajoute la variable width à l'objet instance . . Cette variable agit comme une propriété normale, mais dans ce cas particulier, elle est en lecture seule (seule la variable fget est définie). De plus, fget appelle une fonction définie dans WidthVariable , qui détermine le width à renvoyer.

Cependant, je ne sais pas comment faire cela! Je l’ai essayé avec des propriétés normales, mais j’ai constaté qu’elles ne fonctionnent que sur des classes et non par instance. Veuillez noter que le code que j’utilise doit être le plus semblable possible à celui ci-dessus (c’est-à-dire uniquement dans le code __ init __ de WidthVariable doit définir la variable width , nulle part ailleurs). De plus, self.width ne peut pas fonctionner, car je ne sais pas comment l'appeler comme self.width () , je veux self.width . (car il reste avec le reste de la conception que j'ai).

Pour clarifier, le code complet ressemblerait à ceci:

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
Était-ce utile?

La solution

Etant donné que, comme @Jonathan le dit, les descripteurs (y compris les propriétés) sont par classe et non par instance, le seul moyen d'obtenir différents descripteurs par instance est de laisser chaque instance individualiser sa propre classe. C'est assez superficiel et facile en métaprogrammation ;-) ...:

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

J'ajoute aussi explicitement objet parce que c'est nécessaire (en Python 2. * , et vous dites que c'est ce que vous utilisez !!!) pour faire classes new-type. N'utilisez plus jamais les classes héritées, elles ne se comportent pas correctement en ce qui concerne les propriétés et bien d'autres choses (et pour des raisons de compatibilité ascendante, elles ne le peuvent pas - en Python 3, les classes héritées ont finalement été annihilées; l'exigence de ne plus hériter explicitement d'objet!).

Désormais, tout descripteur placé dans self .__ class __.__ dict __ n’affectera que cette instance, pas une autre. Il y a un peu de surcharge (chaque classe GottaBeMe et donc chaque instance a son propre __ dict __ , etc.), mais rien de trop terrible.

Maintenant, tout ce dont vous avez besoin pour satisfaire la demande initiale est de changer:

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

(renommer également l'objet ) est judicieux pour éviter de piétiner un élément intégré et de donner à la classe un nouveau style, car vous devriez TOUJOURS faire en sorte que CHAQUE classe soit nouveau: style ;-), à:

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

Rien de trop noir-magique, comme vous pouvez le voir! -)

Autres conseils

Je ne comprends pas comment vous avez construit votre exemple, pas plus que ce que vous voulez dire par "propriétés normales". ne travaille que "sur des cours". Voici comment créer une propriété en lecture seule:

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

Je crois que je comprends maintenant votre question et que vous êtes également sans chance .

  

Pour les classes de style nouveau, implicite   les invocations de méthodes spéciales sont   garanti que de fonctionner correctement si   défini sur le type d'un objet, pas dans   le dictionnaire d'instance de l'objet & # 8217; s.

Les descripteurs (utilisés pour implémenter des propriétés) doivent figurer dans le __ dict __ de la classe et ne peuvent pas apparaître dans le __ dict__ de la classe. . En d'autres termes, Python n'est pas Ruby!

J'attends avec joie la correction d'un métaprogrammeur pieux de Python, mais je pense avoir raison.

Vous ne savez pas très bien ce que vous voulez? mais je suppose que vous voulez que obj.width soit personnalisé pour chaque instance Voici un moyen simple d’utiliser des propriétés simples. La propriété width renvoie la valeur renvoyée par un rappel par instance

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

Si le rappel ne peut pas être passé, nous pouvons l'affecter à WidthVariable qui renvoie la largeur en fonction de l'instance

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top