2009-11-04 4 views
7

J'ai du mal à comprendre comment fonctionne un objet classmethod en Python, en particulier dans le contexte des métaclasses et dans __new__. Dans mon cas particulier je voudrais obtenir le nom d'un membre de classmethod, quand je itère par le members qui ont été donnés à __new__.Comment fonctionne un objet classmethod?

Pour les méthodes normales, le nom est simplement stocké dans un attribut __name__, mais pour un classmethod, il n'y a apparemment pas d'attribut de ce type. Je ne vois même pas comment la méthode classMethod est invoquée, car il n'y a pas non plus d'attribut __call__. Est-ce que quelqu'un peut m'expliquer comment fonctionne une méthode de classe ou me diriger vers une documentation? Googling m'a conduit nulle part. Merci!

+0

Je n'ai pas d'idée sur le "missing" '__name__', mais pour être sûr que les méthodes de classe ont un wrapper' __call__'. – mjv

Répondre

18

Un objet classmethod est un descripteur. Vous devez comprendre comment fonctionnent les descripteurs.

En bref, un descripteur est un objet qui présente un procédé __get__, ce qui prend trois arguments: self, un instance et un instance type.

lors de la recherche d'attribut normal, si un objet regardé-up A a une méthode __get__, cette méthode est appelée et ce qu'il retourne est substitué en place pour l'objet A. C'est ainsi que les fonctions (qui sont aussi des descripteurs) deviennent des méthodes liées lorsque vous appelez une méthode sur un objet. Un objet classmethod fonctionne de la même manière. Quand il est recherché, sa méthode __get__ est appelée. Le __get__ d'un classmethod rejette l'argument correspondant au instance (s'il y en avait un) et ne passe que le instance_type lorsqu'il appelle __get__ sur la fonction encapsulée.

Un doodle illustration:

In [14]: def foo(cls): 
    ....:  print cls 
    ....:  
In [15]: classmethod(foo) 
Out[15]: <classmethod object at 0x756e50> 
In [16]: cm = classmethod(foo) 
In [17]: cm.__get__(None, dict) 
Out[17]: <bound method type.foo of <type 'dict'>> 
In [18]: cm.__get__(None, dict)() 
<type 'dict'> 
In [19]: cm.__get__({}, dict) 
Out[19]: <bound method type.foo of <type 'dict'>> 
In [20]: cm.__get__({}, dict)() 
<type 'dict'> 
In [21]: cm.__get__("Some bogus unused string", dict)() 
<type 'dict'> 

Plus d'informations sur les descripteurs peuvent être trouvés ici (entre autres): http://users.rcn.com/python/download/Descriptor.htm

Pour la tâche spécifique d'obtenir le nom de la fonction enveloppée par un classmethod :

In [29]: cm.__get__(None, dict).im_func.__name__ 
Out[29]: 'foo' 
+0

Merci, cela a résolu mon problème! Je me sens un peu bête maintenant puisque je connaissais en principe les descripteurs. Mais j'étais confus de voir qu'une méthode de classe est enveloppée dans un descripteur non-callable :-) – nikow

+0

Désolé, j'ai oublié de souligner à quel point j'apprécie votre réponse très détaillée, c'est tout simplement génial. – nikow

1

This ressemble à il a les marchandises.

+0

Merci, je n'étais pas au courant du terme Metamethods, donc c'était une lecture intéressante. Mais j'ai peur qu'il n'y ait pas beaucoup d'informations sur l'objet classmethod lui-même. – nikow

Questions connexes