当我尝试在类的主体内使用静态方法,并使用内置的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 :(得分:136)
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对象有某种存储原始函数的属性,但我不知道具体细节。本着教别人钓鱼而不是给他们钓鱼的精神,这就是我所做的调查和发现(我的Python会话中的C&amp; 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 :(得分:17)
这是我喜欢的方式:
class Klass(object):
@staticmethod
def stat_func():
return 42
_ANS = stat_func.__func__()
def method(self):
return self.__class__.stat_func() + self.__class__._ANS
由于DRY principle,我更喜欢这个解决方案Klass.stat_func
。
让我想起Python 3中的reason why there is a new super()
:)
但我同意其他人的意见,通常最好的选择是定义模块级功能。
例如使用@staticmethod
函数,递归可能看起来不太好(您需要通过调用Klass.stat_func
内的Klass.stat_func
来破坏DRY原则。那是因为你没有在静态方法中引用self
。
使用模块级功能,一切看起来都不错。
答案 2 :(得分:9)
这是因为staticmethod是一个描述符,需要一个类级属性fetch来运行描述符协议并获得真正的可调用。
来自源代码:
可以在类(例如
C.f()
)或实例上调用它 (例如C().f()
);除了类之外,该实例将被忽略。
但是在定义时不是直接来自类内部。
但正如一位评论者提到的,这根本不是一个“Pythonic”设计。只需使用模块级功能。
答案 3 :(得分:8)
在类定义之后注入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
答案 4 :(得分:8)
这个解决方案怎么样?它不依赖于@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
答案 5 :(得分:1)
根据下面的博客,在类中调用静态方法时,调用函数必须是类方法,因此在方法定义中添加@classmethod
可以解决问题。
The definitive guide on how to use static, class or abstract methods in Python
答案 6 :(得分:0)
如果“核心问题”是使用函数分配类变量,则另一种方法是使用元类(它是“烦人的”和“魔术的”,我同意应该在类内部调用静态方法,但不幸的是,不是)。这样,我们可以将行为重构为一个独立的函数,而不会使类混乱。
export class AppComponent implements OnInit {
constructor(private invokeService: CallWSService) { }
resultService: object;
ngOnInit(): void {
this.invokeService.callGetMethodExample("http://dummy.restapiexample.com/api/v1/employees",this.responseFunc);
}
responseFunc (result: any) : any {
console.log(result);
this.resultService = result;
console.log(this.resultService);
}
doInError (result: any) : any {
console.log(result);
}
}
在“现实世界”中使用此替代方法可能会出现问题。我不得不使用它来覆盖Django类中的类变量,但是在其他情况下,最好使用其他答案中的一种。