2009-06-04 7 views
4

J'essaye d'implémenter la fonction infer_class qui, étant donné une méthode, détermine la classe à laquelle appartient la méthode.Comment déduire la classe à laquelle appartient @staticmethod?

Jusqu'à présent, je quelque chose comme ceci:

import inspect 

def infer_class(f): 
    if inspect.ismethod(f): 
     return f.im_self if f.im_class == type else f.im_class 
    # elif ... what about staticmethod-s? 
    else: 
     raise TypeError("Can't infer the class of %r" % f) 

Il ne fonctionne pas pour @ staticmethod-s parce que je ne pouvais pas trouver un moyen d'y parvenir.

Des suggestions?

Voici infer_class en action:

>>> class Wolf(object): 
...  @classmethod 
...  def huff(cls, a, b, c): 
...   pass 
...  def snarl(self): 
...   pass 
...  @staticmethod 
...  def puff(k,l, m): 
...   pass 
... 
>>> print infer_class(Wolf.huff) 
<class '__main__.Wolf'> 
>>> print infer_class(Wolf().huff) 
<class '__main__.Wolf'> 
>>> print infer_class(Wolf.snarl) 
<class '__main__.Wolf'> 
>>> print infer_class(Wolf().snarl) 
<class '__main__.Wolf'> 
>>> print infer_class(Wolf.puff) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 6, in infer_class 
TypeError: Can't infer the class of <function puff at ...> 
+1

Vous avez la source, vous pouvez lire la classe parente. Pourquoi avez-vous besoin de cela? Qu'est-ce que vous essayez d'accomplir? –

+2

Supposons que je souhaite écrire une fonction qui stocke temporairement une fonction ou une méthode (pour intercepter des appels ou autre, à des fins de test). Pour pouvoir faire cela, j'ai besoin de deux ingrédients: l'objet qui contient la fonction, et le nom de la fonction, de sorte que je puisse faire 'setattr (obj, func_name, my_stub)'. Si f est une fonction au niveau du module, j'utilise 'inspect.getmodule (f)' pour obtenir l'objet et 'f .__ name__' pour obtenir son nom. Pour les méthodes de classe et les méthodes d'instance, j'utilise le code ci-dessus. Pour les méthodes statiques, je n'ai pas de chance, semble-t-il. –

Répondre

3

C'est parce que staticmethods ne sont vraiment pas des méthodes. Le descripteur staticmethod renvoie la fonction d'origine telle quelle. Il n'y a aucun moyen d'obtenir la classe par laquelle la fonction a été accédée. Mais il n'y a pas vraiment de raison d'utiliser staticmethods pour les méthodes, utilisez toujours classmethods. La seule utilisation que j'ai trouvée pour staticmethods est de stocker des objets de fonction en tant qu'attributs de classe et de ne pas les transformer en méthodes.

+6

-1: "Mais il n'y a pas vraiment de raison d'utiliser staticmethods pour les méthodes, utilisez toujours classmethods." Voulez-vous dire instancemethods ou classmethods? Il y a des cas d'utilisation valides pour staticmethods, parfois il y a de "vraies raisons" de les utiliser. – nikow

+2

Je suis intéressé où une méthode statique serait préférable à une méthode de classe? Comme je l'ai dit, la seule utilité est de stocker des fonctions en tant qu'attributs de classe. (et je ne considère pas "mais je n'aime pas le paramètre cls" un argument convaincant) –

+2

+1 D'accord. En outre, je n'ai jamais vu une utilisation de staticmethod en Python pour stocker un objet fonction en tant que classe attr. –

3

J'ai du mal à me mettre à réellement recommander, mais il ne semble pas fonctionner pour les cas simples, au moins:

import inspect 

def crack_staticmethod(sm): 
    """ 
    Returns (class, attribute name) for `sm` if `sm` is a 
    @staticmethod. 
    """ 
    mod = inspect.getmodule(sm) 
    for classname in dir(mod): 
     cls = getattr(mod, classname, None) 
     if cls is not None: 
      try: 
       ca = inspect.classify_class_attrs(cls) 
       for attribute in ca: 
        o = attribute.object 
        if isinstance(o, staticmethod) and getattr(cls, sm.__name__) == sm: 
         return (cls, sm.__name__) 
      except AttributeError: 
       pass 
+0

Ou peut-être juste 1 ligne: next ((k pour k, v dans sys.modules [sm .__ module __] .__ dict __. Items() si getattr (v, sm .__ nom __, None) est sm), None) – parity3

Questions connexes