mar*_*eau 134 python static-methods decorator
当我尝试在类的主体内使用静态方法,并使用内置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
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
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
Run Code Online (Sandbox Code Playgroud)
我理解为什么会发生这种情况(描述符绑定),并且可以通过_stat_func()
在上次使用后手动转换为static方法来解决它,如下所示:
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
Run Code Online (Sandbox Code Playgroud)
所以我的问题是:
是否更好,如更清洁或更"Pythonic",如何实现这一目标?
Ben*_*Ben 152
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
Run Code Online (Sandbox Code Playgroud)
顺便说一句,虽然我怀疑staticmethod对象有某种存储原始函数的属性,但我不知道具体细节.本着教别人钓鱼而不是给他们钓鱼的精神,这就是我所做的调查和发现(我的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>
Run Code Online (Sandbox Code Playgroud)
在交互式会话中进行类似的挖掘(dir
非常有用)通常可以很快解决这些问题.
Jan*_*cak 22
这是我喜欢的方式:
class Klass(object):
@staticmethod
def stat_func():
return 42
_ANS = stat_func.__func__()
def method(self):
return self.__class__.stat_func() + self.__class__._ANS
Run Code Online (Sandbox Code Playgroud)
Klass.stat_func
由于DRY原则,我更喜欢这种解决方案.让我想起Python 3中有一个新super()
的原因 :)
但我同意其他人,通常最好的选择是定义模块级功能.
例如使用@staticmethod
函数,递归可能看起来不太好(你需要通过调用Klass.stat_func
内部来破坏DRY原则Klass.stat_func
).那是因为你没有引用self
内部静态方法.使用模块级功能,一切看起来都不错.
Kei*_*ith 10
这是因为staticmethod是一个描述符,需要一个类级属性fetch来运用描述符协议并获得真正的可调用.
从源代码:
它可以在类(例如
C.f()
)或实例(例如C().f()
)上调用; 除了类之外,该实例被忽略.
但是在定义时不是直接来自类内部.
但正如一位评论者提到的,这根本不是一个"Pythonic"设计.只需使用模块级功能.
那么在类定义之后注入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
Run Code Online (Sandbox Code Playgroud)
这个解决方案怎么样?它不依赖于@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
Run Code Online (Sandbox Code Playgroud)