8
votes

Décorer une méthode de classe après @property

Je veux envelopper toutes les méthodes de divers objets sauf __ init __ à l'aide d'un décorateur. xxx

Cependant, l'emballage d'une instance de propriété résulte équivalent à ceci: xxx

Lorsque le résultat souhaité est quelque chose équivalent à ceci: xxx

Il semble que les attributs d'un objet de propriété soient lus - empêcher la modification de la fonction après la charge de la propriété. Je ne suis pas trop à l'aise avec le niveau de hackerie requis déjà et je préfère ne pas approfondir dans l'objet de propriété de toute façon.

La seule autre solution que je peux voir est de générer une métaclasse sur la mouche que je espérait éviter. Je manque quelque chose d'évident?


1 commentaires

Avez-vous perçu que dans ce code, après avoir exécuté SelevedObject's init une fois qu'il modifie la classe d'origine, vous n'avez donc plus une version non enveloppée de celle-ci?


3 Réponses :


2
votes

Après un bit d'erreur et une erreur, je suis proposé la solution suivante. Tout d'abord, créez une classe d'assistance qui imitera un descripteur décoré: xxx pré>

puis, si vous voyez une propriété, enveloppez-la: P>

>>> inst = WrappedObject(MyObject)()
>>> print inst.result
Calling decorated function <method-wrapper '__get__' of property object at 0x00BB6930>
Some derived property


0 commentaires

0
votes

Vous pouvez introduire des décorateurs "paresseux", qui sont appliqués après votre propre décorateur, par exemple: xxx

.. puis utilisez @lazy_property au lieu de < Code> @Property . (AVERTISSEMENT: Code non testé, mais j'espère que vous obtenez l'idée ...)


0 commentaires

6
votes

Il y a quelques autres problèmes dans cet échantillon, mais pour pouvoir remettre en question, tout ce que vous avez à faire est, lorsque vous enveloppez une propriété

Lorsque vous enveloppez une propriété, enveloppez sa méthode __GET__ à la place: P>

class WrappedObject(object):

    def __init__(self, cls):
        dct = cls.__dict__.copy()
        for attr, item in dct.items():
            if attr != '__init__' and callable(item):
                dct[attr] =  my_decorator(item)
            elif  isinstance(item, property):
                new_property = property(my_decorator(item.__get__), item.__set__, item.__delattr__)
                dct[attr] = new_property
        self._cls = type("wrapped_" + cls.__name__, (cls,), dct)

    def __call__(self, *args, **kwargs):
        return self._cls(*args, **kwargs)


1 commentaires

Je suis d'accord que la création d'une sous-classe serait beaucoup plus chère, je préfère éviter la correction de la classe d'origine.