在类体内调用类的静态方法?
当我尝试从类的主体中使用静态方法,并使用内置静态方法函数作为装饰器来定义静态方法时,如下所示:
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”,方法来实现这一点?
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
是非常有用的)通常可以很快解决这类问题。
这是由于staticmethod是一个描述符,并且需要一个类级属性获取来执行描述符协议并获得真正的可调用性。
从源代码:
它可以在类(例如
Cf()
)或实例(例如C().f()
)上调用; 该实例被忽略,除了它的类。
但是在定义的时候并不是直接从课堂内部进行。
但正如一位评论者所说,这根本不是一个“Pythonic”devise。 只需使用模块级别的function。
这个解决scheme呢? 它不依赖于@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 def stat_func(): return 42 _ANS = stat_func.__func__() def method(self): return self.__class__.stat_func() + self.__class__._ANS
由于DRY原则 ,我更喜欢Klass.stat_func
这个解决scheme。 让我想起为什么在Python 3中有一个新的super()
🙂
但是我同意别人的看法,通常最好的select是定义一个模块级别的函数。
比如用@staticmethod
函数,recursion可能看起来不太好(你需要通过调用Klass.stat_func
来打破DRY原则)。 那是因为你没有在静态方法里面引用self
。 使用模块级function,一切都会看起来不错。
在类定义之后注入类属性怎么样?
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中使用静态,类或抽象方法的权威指南