Wywołanie klasy staticmethod wewnątrz ciała klasy?
Kiedy próbuję użyć statycznej metody z wewnątrz ciała klasy i zdefiniować statyczną metodę używając wbudowanej funkcji staticmethod
jako dekoratora, jak to:
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
Dostaję następujący błąd:
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
rozumiem, dlaczego tak się dzieje (Wiązanie deskryptora), i mogę obejść to, ręcznie konwertując _stat_func()
do statycznego methoda po jego ostatnim użyciu, tak:
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
Więc moje pytanie brzmi:
czy są lepsze, jak w czystszym czy bardziej "Pythoniczne", sposoby na to?
6 answers
staticmethod
obiekty najwyraźniej mają atrybut __func__
przechowujący oryginalną funkcję raw (ma to sens, że musiały). Więc to zadziała:
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
Na marginesie, chociaż podejrzewałem, że obiekt staticmethod ma jakiś atrybut przechowujący oryginalną funkcję, nie miałem pojęcia o szczegółach. W duchu uczenia kogoś do łowienia ryb, a nie dawania im ryby, to jest to, co zrobiłem, aby zbadać i dowiedzieć się, że (dosłownie C & P z mojego Pythona sesja): {]}
>>> 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>
Podobne rodzaje kopania w interaktywnej sesji (dir
jest bardzo pomocne) często mogą rozwiązać tego rodzaju pytania bardzo szybko.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-03 23:24:28
Tak wolę:
class Klass(object):
@staticmethod
def stat_func():
return 42
_ANS = stat_func.__func__()
def method(self):
return self.__class__.stat_func() + self.__class__._ANS
Wolę to rozwiązanie od Klass.stat_func
, ze względu na zasadę suchości.
Przypomina mi powód, dla którego jest nowy super()
w Pythonie 3:)
Ale Zgadzam się z innymi, zwykle najlepszym wyborem jest zdefiniowanie funkcji poziomu modułu.
Na przykład w przypadku funkcji @staticmethod
rekurencja może nie wyglądać zbyt dobrze (trzeba by złamać zasadę DRY wywołując Klass.stat_func
wewnątrz Klass.stat_func
). To dlatego, że nie masz odniesienie do self
wewnątrz metody statycznej.
Dzięki funkcji poziomu modułu wszystko będzie wyglądać dobrze.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-10 21:13:31
Jest to spowodowane tym, że staticmethod jest deskryptorem i wymaga atrybutu fetch na poziomie klasy, aby wykonać protokół deskryptora i uzyskać true callable.
Z kodu źródłowego:
Może być wywołana albo na klasie (np.
C.f()
) albo na instancji (np.C().f()
); instancja jest ignorowana z wyjątkiem jej klasy.
Ale nie bezpośrednio z wnętrza klasy podczas jej definiowania.
Ale jak wspomniał jeden z komentatorów, nie jest to tak naprawdę Projekt "Pythonic" w ogóle. Wystarczy użyć funkcji poziomu modułu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-04 00:00:46
Co z tym rozwiązaniem? Nie opiera się na znajomości implementacji @staticmethod
dekoratora. Wewnętrzna Klasa StaticMethod gra jako kontener statycznych funkcji inicjalizacyjnych.
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-15 23:29:10
A co z wprowadzaniem atrybutu klasy po definicji klasy?
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-03 23:21:05
Zgodnie z poniższym blogiem, podczas wywoływania statycznej metody wewnątrz klasy, funkcja wywołująca musi być metodą klasy, więc dodanie @classmethod
do definicji metody może rozwiązać problem.
The definitive guide on how to use static, class or abstract methods in Python
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-28 08:36:05