How does assignment of a function as a class attribute become a method in Python?
1 2 3 4 5 | >>> class A(object): pass >>> def func(cls): pass >>> A.func = func >>> A.func <unbound method A.func> |
此分配如何创建方法?作业为班级做以下工作似乎毫无意义:
- 将函数转换为未绑定的实例方法
- 将
classmethod() 中包装的函数转换为类方法(实际上,这是非常直观的) - 将
staticmethod() 中包装的函数转换为函数
似乎在第一种情况下,应该有一个
但更重要的是,如何准确地将函数分配到类中?什么魔法能解决这三件事?
更令人困惑的是:
1 2 3 4 | >>> A.func <unbound method A.func> >>> A.__dict__['func'] <function func at 0x...> |
但我认为这与检索属性时的描述符有关。我认为这和这里的属性设置没有多大关系。
你说得对,这与描述符协议有关。描述符是如何在Python中实现将接收对象作为方法的第一个参数传递的。您可以从这里阅读关于python属性查找的更多详细信息。下面显示了一个较低的级别,当您执行a.func=func;a.func时会发生什么:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # A.func = func A.__dict__['func'] = func # This just sets the attribute # A.func # The __getattribute__ method of a type object calls the __get__ method with # None as the first parameter and the type as the second. A.__dict__['func'].__get__(None, A) # The __get__ method of a function object # returns an unbound method object if the # first parameter is None. a = A() # a.func() # The __getattribute__ method of object finds an attribute on the type object # and calls the __get__ method of it with the instance as its first parameter. a.__class__.__dict__['func'].__get__(a, a.__class__) # This returns a bound method object that is actually just a proxy for # inserting the object as the first parameter to the function call. |
因此,是在类或实例上查找函数,将其转换为方法,而不是将其分配给类属性。
描述符是magic1,当您从实例或类中检索普通函数时,它会将其转换为绑定或未绑定的方法,因为它们都只是需要不同绑定策略的函数。
请参阅"用户定义的方法"了解一些详细信息,但请注意:
Also notice that this transformation only happens for user-defined functions; other callable objects (and all non-callable objects) are retrieved without transformation.
因此,如果您希望为自己的可调用对象进行这种转换,您可以将其包装在一个函数中,但也可以编写一个描述符来实现自己的绑定策略。
这里是
1 2 3 4 5 6 7 8 | >>> @staticmethod ... def f(): pass >>> class A(object): pass >>> A.f = f >>> A.f <function f at 0x100479398> >>> f <staticmethod object at 0x100492750> |
而使用
1 2 3 4 5 6 7 8 | >>> class C(object): ... def __call__(self): pass >>> c = C() >>> A.c = c >>> A.c <__main__.C object at 0x10048b890> >>> c <__main__.C object at 0x10048b890> |
1具体功能是objects/funcobject.c中的
您必须考虑的是,在Python中,一切都是一个对象。通过确定更容易理解正在发生的事情。如果你有一个函数
python中的对象将其实例属性保存在一个名为
实例方法的第一个参数总是实例对象本身,通常称为
如果理解了这一点,那么分配
在您的示例中,
关于Mtsole对加布里埃尔·赫尔利回答的评论:
不同的是,
点1:您定义的函数
第2点:Python中的类将其属性存储在它们的
那么当您在python中传递一个函数作为class属性的值时会发生什么呢?该函数存储在类"EDOCX1"〔1〕中,通过调用分配给它的属性名,使它成为该类的一个方法。