【问题标题】:Can someone explain how the source code of staticmethod works in python有人能解释一下staticmethod的源代码在python中是如何工作的吗
【发布时间】:2015-11-02 03:50:53
【问题描述】:

首先,我了解装饰器的工作原理。我知道@staticmethod 去掉了签名中的实例参数,使得

class C(object):
    @staticmethod
    def foo():
        print 'foo'
C.foo    //<function foo at 0x10efd4050>
C().foo  //<function foo at 0x10efd4050>

有效。

但是,我不明白 staticmethod 的源代码是如何做到这一点的。

在我看来,当在 staticmethod 中包装方法 foo 时,staticmethod 的实例被实例化,然后 一些魔法 发生了,使 C.foo() 合法。

那么.. 那些魔法会发生什么? staticmethod 做了什么?

我知道关于staticmethods 的大量话题,但没有一个能解决我的疑虑。但也许我没有击中魔法关键字。如果是这样,请告诉我。

寻找staticmethod源代码的朋友请参考https://hg.python.org/cpython/file/c6880edaf6f3/Objects/funcobject.c

【问题讨论】:

    标签: python decorator static-methods python-decorators python-internals


    【解决方案1】:

    staticmethod 对象是descriptor。您缺少的神奇之处在于 Python 在将对象作为类或实例的属性访问时调用了 __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__的第二个参数将一个函数绑定到类,然后还有property对象,将绑定直接转化为函数调用。见How does the @property decorator work?

    【讨论】:

    • 我从 PyCharm IDE 得到源代码..我不知道它是否是真正的副本..oops
    • @user2829759:PyCharm 无法访问实际的源代码(因为它是编译的 C 代码),因此它会通过自省对象为您重建一个 shim。
    • @martijinpieters 是否反映了 C 代码中正在发生的事情?
    • @user2829759:我的 Python 代码版本?绝对地。 PyCharm 反射无法显示在方法中发生了什么,它只能推断出一个签名。
    • @user2829759:但是,__func__ 属性描述是完全错误的。它只是简单地返回被包装的函数(就像__get__ 方法一样,基本上)。 __getattribute____new__ 方法的存在只是令人困惑的事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-13
    • 2023-01-12
    • 1970-01-01
    相关资源
    最近更新 更多