J'ai quelque chose à peu près comme ce qui suit. Fondamentalement, j'ai besoin d'accéder à la classe d'une méthode d'instance à partir d'un décorateur utilisé sur la méthode d'instance dans sa définition.
def decorator(view):
# do something that requires view's class
print view.im_class
return view
class ModelA(object):
@decorator
def a_method(self):
# do some stuff
pass
Le code tel quel donne:
AttributeError: l'objet 'function' n'a pas d'attribut 'im_class'
J'ai trouvé des questions / réponses similaires - le décorateur Python fait oublier à la fonction qu'il appartient à une classe et la classe Get dans le décorateur Python - mais ceux-ci reposent sur une solution de contournement qui saisit l'instance au moment de l'exécution en saisissant le premier paramètre. Dans mon cas, j'appellerai la méthode en fonction des informations glanées dans sa classe, donc j'ai hâte qu'un appel arrive.
inspect.getmro(cls)
pour traiter toutes les classes de base dans le décorateur de classe pour prendre en charge l'héritage.inspect
à la rescousse stackoverflow.com/a/1911287/202168Depuis python 3.6, vous pouvez utiliser
object.__set_name__
pour accomplir cela de manière très simple. Le document indique qu'il__set_name__
est "appelé au moment où le propriétaire de la classe propriétaire est créé". Voici un exemple:Notez qu'il est appelé au moment de la création de la classe:
Si vous souhaitez en savoir plus sur la création des classes et en particulier sur le moment exact de leur
__set_name__
appel, vous pouvez vous référer à la documentation sur "Création de l'objet de classe" .la source
@class_decorator('test', foo='bar')
def decorator(*args, **kwds): class Descriptor: ...; return Descriptor
__set_name__
bien que j'utilise Python 3.6+ depuis longtemps.hello
n'est pas une méthode, mais plutôt un objet de typeclass_decorator
.if TYPE_CHECKING
pour définirclass_decorator
comme un décorateur normal retournant le type correct.Comme d'autres l'ont souligné, la classe n'a pas été créée au moment où le décorateur est appelé. Cependant , il est possible d'annoter l'objet fonction avec les paramètres du décorateur, puis de re-décorer la fonction dans la
__new__
méthode de la métaclasse . Vous devrez accéder__dict__
directement à l'attribut de la fonction , car au moins pour moi, cela afunc.foo = 1
abouti à une AttributeError.la source
setattr
devrait être utilisé au lieu d'accéder__dict__
Comme Mark le suggère:
Ce code montre comment cela peut fonctionner en utilisant le post-traitement automatique:
La sortie donne:
Notez que dans cet exemple:
J'espère que cela t'aides
la source
Comme Ants l'a indiqué, vous ne pouvez pas obtenir de référence à la classe à partir de la classe. Cependant, si vous souhaitez faire la distinction entre différentes classes (sans manipuler l'objet de type de classe réel), vous pouvez transmettre une chaîne pour chaque classe. Vous pouvez également transmettre les autres paramètres de votre choix au décorateur en utilisant des décorateurs de style classe.
Impressions:
Voir également la page de Bruce Eckel sur les décorateurs.
la source
@decorator('Bar')
à- dire par opposition à@Decorator('Bar')
.Ce que fait flask-classy est de créer un cache temporaire qu'il stocke sur la méthode, puis il utilise autre chose (le fait que Flask enregistrera les classes en utilisant une
register
méthode de classe) pour encapsuler réellement la méthode.Vous pouvez réutiliser ce modèle, cette fois en utilisant une métaclasse afin de pouvoir encapsuler la méthode au moment de l'importation.
Sur la classe réelle (vous pouvez faire la même chose en utilisant une métaclasse):
Source: https://github.com/apiguy/flask-classy/blob/master/flask_classy.py
la source
Le problème est que lorsque le décorateur est appelé, la classe n'existe pas encore. Essaye ça:
Ce programme affichera:
Comme vous le voyez, vous allez devoir trouver une manière différente de faire ce que vous voulez.
la source
Voici un exemple simple:
La sortie est:
la source
C'est une vieille question mais je suis tombée sur le vénusien. http://venusian.readthedocs.org/en/latest/
Il semble avoir la capacité de décorer des méthodes et de vous donner accès à la fois à la classe et à la méthode. Notez que l'appel
setattr(ob, wrapped.__name__, decorated)
n'est pas la manière typique d'utiliser vénusien et va quelque peu à l'encontre du but.Quoi qu'il en soit ... l'exemple ci-dessous est complet et devrait fonctionner.
la source
Function ne sait pas s'il s'agit d'une méthode au point de définition, lorsque le code du décorateur s'exécute. Ce n'est qu'en cas d'accès via l'identifiant de classe / instance qu'il peut connaître sa classe / instance. Pour surmonter cette limitation, vous pouvez décorer par objet descripteur pour retarder le code de décoration réel jusqu'au temps d'accès / d'appel:
Cela vous permet de décorer des méthodes individuelles (statiques | classe):
Vous pouvez maintenant utiliser le code décorateur pour l'introspection ...
... et pour changer le comportement des fonctions:
la source
</sigh>
Comme d'autres réponses l'ont souligné, le décorateur est une chose très fonctionnelle, vous ne pouvez pas accéder à la classe à laquelle appartient cette méthode car la classe n'a pas encore été créée. Cependant, il est tout à fait correct d'utiliser un décorateur pour "marquer" la fonction et ensuite utiliser des techniques de métaclasse pour traiter la méthode plus tard, car à l'
__new__
étape, la classe a été créée par sa métaclasse.Voici un exemple simple:
Nous utilisons
@field
pour marquer la méthode comme un champ spécial et la traiter dans une métaclasse.la source
if inspect.isfunction(v) and getattr(k, "is_field", False):
il devrait l'être à lagetattr(v, "is_field", False)
place.Vous aurez accès à la classe de l'objet sur lequel la méthode est appelée dans la méthode décorée que votre décorateur doit renvoyer. Ainsi:
En utilisant votre classe ModelA, voici ce que cela fait:
la source
Je veux juste ajouter mon exemple car il a toutes les choses auxquelles je pourrais penser pour accéder à la classe à partir de la méthode décorée. Il utilise un descripteur comme le suggère @tyrion. Le décorateur peut prendre des arguments et les transmettre au descripteur. Il peut traiter à la fois une méthode dans une classe ou une fonction sans classe.
la source