2009-06-04 7 views
4

Я пытаюсь реализовать функцию infer_class, которая, учитывая метод, вычисляет класс, к которому принадлежит метод.Как определить класс, которому принадлежит @staticmethod?

До сих пор у меня есть что-то вроде этого:

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) 

Это не работает для @ STATICMETHOD-s, потому что я не был в состоянии придумать способ для достижения этой цели.

Любые предложения?

Вот в действии infer_class:

>>> 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

У вас есть источник, вы можете прочитать родительский класс. Зачем тебе это нужно? Что вы пытаетесь достичь? –

+2

Предположим, я хотел написать функцию, которая временно заглушает функцию или метод (перехватывать вызовы или что-то еще для целей тестирования). Чтобы это сделать, мне нужны два компонента: объект, содержащий функцию, и имя функции, чтобы я мог делать 'setattr (obj, func_name, my_stub)'. Если f является модульной функцией, я использую 'inspect.getmodule (f)' для получения объекта и 'f .__ name__' для получения своего имени. Для методов класса и методов экземпляра я использую приведенный выше код. Казалось бы, для статических методов мне повезло. –

ответ

3

Это потому, что staticmethods на самом деле не методы. Дескриптор staticmethod возвращает исходную функцию как есть. Невозможно получить класс, через который была доступна эта функция. Но нет никаких оснований использовать staticmethods для методов в любом случае, всегда используйте classmethods.

Единственное, что я нашел для staticmethods, это хранить объекты функций как атрибуты класса и не включать их в методы.

+6

-1: «Но нет никакой причины использовать static методы для методов в любом случае, всегда используйте classmethods». Вы имеете в виду примеры методов или классов? Существуют действительные варианты использования для staticmethods, иногда есть «реальные причины» для их использования. – nikow

+2

Мне интересно, где бы статический метод был бы предпочтительным для класса? Как я уже сказал, единственная убедительная утилита - это сохранение функций как атрибутов класса. (и я не считаю «но мне не нравится параметр cls» - убедительный аргумент) –

+2

+1 Согласен. Я также никогда не видел использования для staticmethod в Python, кроме того, для хранения объекта функции в качестве класса attr. –

3

У меня проблемы принося себя на самом деле рекомендовать это, но это не похоже на работу для простых случаев, по крайней мере:

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

Или, может быть, только 1 строка: следующая ((k для k, v в sys.modules [sm .__ module __] .__ dict __. Items(), если getattr (v, sm .__ name __, None) is sm), None) – parity3