问题:在类主体中调用类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()
在上次使用后手动将其转换为静态方法来解决此问题,如下所示:
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
所以我的问题是:
是否有更好的方法(如更清洁或更“ Pythonic”的)来完成此任务?
回答 0
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
顺便说一句,尽管我怀疑静态方法对象具有某种存储原始功能的属性,但我对具体细节一无所知。本着教别人钓鱼而不是给他们钓鱼的精神,这就是我所做的调查,并发现了这一点(Python会话中的C&P):
>>> 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
非常有帮助)通常可以非常快速地解决这些问题。
回答 1
这是我更喜欢的方式:
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
由于DRY原理,我更喜欢这种解决方案。让我想起了Python 3中有新功能super()
的原因 :)
但是我与其他人一样,通常最好的选择是定义一个模块级别的功能。
例如带@staticmethod
功能的递归可能看起来不太好(您需要通过调用Klass.stat_func
inside 来打破DRY原理Klass.stat_func
)。那是因为您没有引用self
内部静态方法。有了模块级功能,一切都会看起来不错。
回答 2
在类定义之后注入class属性怎么办?
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
回答 3
这是由于staticmethod是描述符,并且需要获取类级别的属性才能执行描述符协议并获得真正的可调用对象。
从源代码:
可以在类(例如
C.f()
)或实例(例如C().f()
)上调用它;该实例除其类外均被忽略。
但是在定义类时,不能直接从类内部进行。
但是正如一位评论者所提到的,这根本不是一个真正的“ Pythonic”设计。只需使用模块级功能即可。
回答 4
那这个解决方案呢?它不依赖@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