有人可以解释一下 staticmethod 的源代码在 python 中是如何工作的吗?
Can someone explain how the source code of staticmethod works in python
首先,我了解装饰器通常是如何工作的。而且我知道 @staticmethod
剥离了签名中的实例参数,使得
class C(object):
@staticmethod
def foo():
print 'foo'
C.foo //<function foo at 0x10efd4050>
C().foo //<function foo at 0x10efd4050>
有效。
但是,我不明白 staticmethod
的 sourcec 代码是如何做到这一点的。
在我看来,当在 staticmethod
中包装方法 foo
时, staticmethod
的一个实例被实例化,然后 一些魔法 发生了, 使 C.foo()
合法。
那么..那些魔法会发生什么? staticmethod
做了什么?
我知道关于 staticmethods
的大量主题,但其中 none 解决了我的疑虑。但也许我没有击中魔法关键字。如果是这样,请告诉我。
如需staticmethod
源码请参考https://hg.python.org/cpython/file/c6880edaf6f3/Objects/funcobject.c
一个staticmethod
对象是一个descriptor。您缺少的魔法是 Python 在将对象作为 class 或实例上的属性访问时调用 __get__
方法。
因此,以 C.foo
访问对象会导致 Python 将其转换为 C.__dict__['foo'].__get__(None, C)
,而 instance_of_C.foo
变为 type(instace_of_C).__dict__['foo'].__get__(instance_of_C, type(instance_of_C))
。
staticmethod
对象是 defined in C code,但 Python 中的等效对象是:
class staticmethod(object):
def __init__(self, callable):
self.f = callable
def __get__(self, obj, type=None):
return self.f
@property
def __func__(self):
return self.f
其中 self.f
是原始包装函数。
所有这些都是必需的,因为函数本身也是描述符;它是为您提供方法对象的描述符协议(有关详细信息,请参阅 python bound and unbound method object)。因为他们也有一个 __get__
方法,没有 staticmethod
对象包装函数,所以 functionobj.__get__
调用生成一个方法对象,传递一个 self
参数。
还有一个classmethod
,它使用descriptor.__get__
的第二个参数绑定一个函数到class,然后有property
个对象,将绑定直接转换为函数调用。参见 How does the @property decorator work?。
静态方法的源代码实际上是用 C 语言编写的,但您可以用这个简短的片段复制它的行为:
class staticmethod:
def __init__(self, decorated_method):
self.decorated_method = decorated_method
def __get__(self, instance, owner):
return self.decorated_method
这里是对上面代码片段的简要解释,来自这个 article 我写道:“方法是描述符,因此实现了魔法方法 __get__
。 @staticmethod
是一个 class 装饰器,重新实现 __get__
并使它成为 return 一个未绑定到它所属对象的装饰方法的版本。因此,装饰方法没有隐式参数 self
。”如果您不清楚 描述符、绑定方法 或 class 描述符 的概念, 它们在文章中有解释。
首先,我了解装饰器通常是如何工作的。而且我知道 @staticmethod
剥离了签名中的实例参数,使得
class C(object):
@staticmethod
def foo():
print 'foo'
C.foo //<function foo at 0x10efd4050>
C().foo //<function foo at 0x10efd4050>
有效。
但是,我不明白 staticmethod
的 sourcec 代码是如何做到这一点的。
在我看来,当在 staticmethod
中包装方法 foo
时, staticmethod
的一个实例被实例化,然后 一些魔法 发生了, 使 C.foo()
合法。
那么..那些魔法会发生什么? staticmethod
做了什么?
我知道关于 staticmethods
的大量主题,但其中 none 解决了我的疑虑。但也许我没有击中魔法关键字。如果是这样,请告诉我。
如需staticmethod
源码请参考https://hg.python.org/cpython/file/c6880edaf6f3/Objects/funcobject.c
一个staticmethod
对象是一个descriptor。您缺少的魔法是 Python 在将对象作为 class 或实例上的属性访问时调用 __get__
方法。
因此,以 C.foo
访问对象会导致 Python 将其转换为 C.__dict__['foo'].__get__(None, C)
,而 instance_of_C.foo
变为 type(instace_of_C).__dict__['foo'].__get__(instance_of_C, type(instance_of_C))
。
staticmethod
对象是 defined in C code,但 Python 中的等效对象是:
class staticmethod(object):
def __init__(self, callable):
self.f = callable
def __get__(self, obj, type=None):
return self.f
@property
def __func__(self):
return self.f
其中 self.f
是原始包装函数。
所有这些都是必需的,因为函数本身也是描述符;它是为您提供方法对象的描述符协议(有关详细信息,请参阅 python bound and unbound method object)。因为他们也有一个 __get__
方法,没有 staticmethod
对象包装函数,所以 functionobj.__get__
调用生成一个方法对象,传递一个 self
参数。
还有一个classmethod
,它使用descriptor.__get__
的第二个参数绑定一个函数到class,然后有property
个对象,将绑定直接转换为函数调用。参见 How does the @property decorator work?。
静态方法的源代码实际上是用 C 语言编写的,但您可以用这个简短的片段复制它的行为:
class staticmethod:
def __init__(self, decorated_method):
self.decorated_method = decorated_method
def __get__(self, instance, owner):
return self.decorated_method
这里是对上面代码片段的简要解释,来自这个 article 我写道:“方法是描述符,因此实现了魔法方法 __get__
。 @staticmethod
是一个 class 装饰器,重新实现 __get__
并使它成为 return 一个未绑定到它所属对象的装饰方法的版本。因此,装饰方法没有隐式参数 self
。”如果您不清楚 描述符、绑定方法 或 class 描述符 的概念, 它们在文章中有解释。