Вызов класса staticmethod в теле класса?
когда я пытаюсь использовать статический метод в теле класса, и определить статический метод с помощью встроенного staticmethod функция в качестве декоратора, как это:
class Klass(object):
@staticmethod # use as decorator
def _stat_func():
return 42
_ANS = _stat_func() # call the staticmethod
def method(self):
ret = Klass._stat_func() + Klass._ANS
return ret
я получаю следующее сообщение об ошибке:
Traceback (most recent call last):<br>
File "call_staticmethod.py", line 1, in <module>
class Klass(object):
File "call_staticmethod.py", line 7, in Klass
_ANS = _stat_func()
TypeError: 'staticmethod' object is not callable
Я понимаю, почему это происходит (дескриптор привязки), и может работать вокруг него путем ручного преобразования _stat_func() в staticmethod после его последнего использования, например, так:
class Klass(object):
def _stat_func():
return 42
_ANS = _stat_func() # use the non-staticmethod version
_stat_func = staticmethod(_stat_func) # convert function to a static method
def method(self):
ret = Klass._stat_func() + Klass._ANS
return ret
так что мой вопрос это:
там лучше, как чище и более "подходящие для Python", способов сделать это?
6 ответов:
staticmethodобъекты, по-видимому, имеют__func__атрибут, хранящий исходную необработанную функцию (имеет смысл, что они должны были). Так что это будет работать:class Klass(object): @staticmethod # use as decorator def stat_func(): return 42 _ANS = stat_func.__func__() # call the staticmethod def method(self): ret = Klass.stat_func() return ret
в стороне, хотя я подозревал, что объект staticmethod имеет какой-то атрибут, хранящий исходную функцию, я понятия не имел о специфике. В духе обучения кого-то ловить рыбу, а не давать им рыбу, это то, что я сделал, чтобы исследовать и выяснить это (буквально C&P от моего Python сессия):
>>> class Foo(object): @staticmethod def foo(): return 3 global z z = foo >>> z <staticmethod object at 0x0000000002E40558> >>> Foo.foo <function foo at 0x0000000002E3CBA8> >>> dir(z) ['__class__', '__delattr__', '__doc__', '__format__', '__func__', '__get__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__'] >>> z.__func__ <function foo at 0x0000000002E3CBA8>подобные виды копания в интерактивном сеансе (
dirочень полезно) часто может решить такие вопросы очень быстро.
вот как я предпочитаю:
class Klass(object): @staticmethod def stat_func(): return 42 _ANS = stat_func.__func__() def method(self): return self.__class__.stat_func() + self.__class__._ANSЯ предпочитаю это решение
Klass.stat_funcиз-за сухой принцип. Напоминает мне о причина, почему есть новыйsuper()в Python 3 :)но я согласен с другими, обычно лучшим выбором является определение функции уровня модуля.
например,
@staticmethodфункция, рекурсия может выглядеть не очень хорошо (вам нужно будет сломать сухой принцип, вызвавKlass.stat_funcвнутриKlass.stat_func). Это потому что у вас нет ссылки наselfвнутри статического метода. С функцией уровня модуля все будет выглядеть нормально.
Это связано с тем, что staticmethod является дескриптором и требует выборки атрибута уровня класса для выполнения протокола дескриптора и получения истинного вызываемого объекта.
в исходном коде:
Он может быть вызван либо на класс (например
C.f()) или на экземпляре (например,C().f()); экземпляр игнорируется, за исключением его класса.но не непосредственно из класса, пока он определяется.
но как один комментатор упомянутый, это на самом деле не "Питонический" дизайн вообще. Просто используйте функцию модуля.
Как насчет этого решения? Он не полагается на знание
@staticmethodреализация декоратора. Внутренний класс StaticMethod играет как контейнер статических функций инициализации.class Klass(object): class StaticMethod: @staticmethod # use as decorator def _stat_func(): return 42 _ANS = StaticMethod._stat_func() # call the staticmethod def method(self): ret = self.StaticMethod._stat_func() + Klass._ANS return ret
Как насчет введения атрибута класса после определения класса?
class Klass(object): @staticmethod # use as decorator def stat_func(): return 42 def method(self): ret = Klass.stat_func() return ret Klass._ANS = Klass.stat_func() # inject the class attribute with static method value
согласно блогу ниже, при вызове статического метода в классе вызывающая функция должна быть методом класса, поэтому добавление
@classmethodк вашему определению метода может решить проблему.окончательное руководство по использованию статических, классовых или абстрактных методов в Python
Comments