我有一个场景,其中有带有静态方法的对象。它们都是使用外部def build_hello()
作为类变量构建的。
def build_hello(name: str):
@staticmethod
def hello_fn():
return "hello my name is "
# Assign an attribute to the staticmethod so it can be used across all classes
hello_fn.first_name = name
print(hello_fn() + hello_fn.first_name) # This works
return hello_fn
class World:
hello_fn = build_hello("bob")
# Error, function object has no attribute "first_name"
World.hello_fn.first_name
这是怎么回事?我能够在函数调用hello_fn()
中访问属性build_hello()
。但是当将其添加到我的对象时,该属性不再列出。
如果我调用dir()
静态方法,我也看不到它:
dir(World.hello_fn)
['__annotations__',
'__builtins__',
'__call__',
'__class__',
'__closure__',
'__code__',
'__defaults__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__get__',
'__getattribute__',
'__getstate__',
'__globals__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__kwdefaults__',
'__le__',
'__lt__',
'__module__',
'__name__',
'__ne__',
'__new__',
'__qualname__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__type_params__']
在 Python 中,从类中检索方法(无论是常规实例方法、类方法还是静态方法)都使用底层机制在请求时实际构建方法对象(通常使用运算符
.
,也可以使用调用getattr(...)
):绑定到类命名空间的对象有一个
__get__
方法 - 正是这个__get__
方法构建了被检索的对象,并且它将被调用为方法 - 因此,如果它是一个类方法,它将cls
被插入为第一个参数,或者self
常规方法的参数,而对于静态方法则不插入任何内容。问题是,
__get__
常规函数的方法将使其表现得像普通实例方法。@classmethod
和@staticmethod
装饰器对方法有不同的行为__get__
,在调用方法时产生所需的最终效果。因此,当您创建一个
staticmethod
包装函数时,它不是在您执行时检索的这个MyClass.mymethod
对象- 而是__get__
@staticmethod 方法返回的任何对象 - 在这种情况下,它会按原样返回底层函数。TL;DR:在用调用包装它之前,将您的属性放入底层函数中
staticmethod
,因为这就是返回的内容World.hello_fn
:__func__
或者,您可以通过静态方法对象的属性应用装饰器后到达该函数:您将属性附加到 的实例
staticmethod
。由于描述符协议的工作方式及其staticmethod
实现方式,World.hello_fn
不是的实例staticmethod
,而是function
静态方法包装 的对象。另外,
staticmethod
自 Python 3.10 起,实例才可直接调用。在此之前,您的hello_fn()
调用会失败。