下面的简短python代码可以工作,但我期待一个错误

t98cgbkg  于 2023-11-16  发布在  Python
关注(0)|答案(1)|浏览(73)
class MyClass: pass
def myfunction(): print('hi')

MyClass.foo = myfunction
obj = MyClass()
obj.foo = myfunction

MyClass.foo()
obj.foo()

字符串
我正在学习Python,无法理解最后两行是如何工作的,而不会出现任何矛盾的错误。我先用class对象赋值和调用同一个myfunction,然后用instance对象赋值和调用,我所理解的是,当用instance对象调用一个方法时,python隐式地将示例传递给方法。因此,我希望最后两行中的一行能正常工作,但不是两行都能正常工作。糊涂了

mkh04yzy

mkh04yzy1#

作为第一个近似,当你写

obj.foo

字符串
Python尝试通过以下方式查找foo
1.检查obj是否具有名为foo的属性,然后
1.检查obj的类(obj.__class__,这里是MyClass)是否具有属性foo
如果在第一步中,找到了一个名为foo的属性,那么该对象将被返回。无论该对象是 * 什么 (无论是函数对象还是其他对象),它都会被返回。这就是代码中发生的情况:obj有一个名为foo的属性,因此该对象将被返回-MyClass.foo永远不会被考虑。
如果obj没有属性foo,那么我们进入第二步。在这里,一些特殊的行为开始了:Descriptor Protocol。如果obj.__class__有一个名为foo的属性,那么在返回该对象之前,Python首先检查foo是否是描述符。如果是,那么不是返回foo,Python将返回foo.__get__(obj)
这 * 是方法的工作方式。方法只是通过描述符协议访问的类的函数属性。
如果你只写

class MyClass: 
    pass

def myfunction(): 
    print('hi')

MyClass.foo = myfunction

obj = MyClass()
obj.foo()


那么你就有问题了。现在,obj * 没有 * 一个名为foo的属性,所以访问obj.fooMyClass上查找fooMyClass确实有一个名为foo的属性,它绑定到myfunctionmyfunction,像所有函数对象一样,是一个描述符,所以Python调用myfunction.__get__(obj),它返回一个绑定方法对象。这个绑定方法对象是一个可调用对象,当它被调用时,它会尝试将obj传递给myfunction。由于myfunction不接受任何参数,这将产生一个错误,正如你最初怀疑的那样:

TypeError: myfunction() takes 0 positional arguments but 1 was given


1完整的属性查找过程要复杂得多。请参见3.3.2.从Python数据模型文档中自定义属性访问以了解更大的情况。

相关问题