我创建了一些测试代码,但我无法真正理解它为什么起作用。
在使用前不应该定义moo
吗?
#!/usr/bin/python3
class Test():
def __init__(self):
self.printer = None
def foo(self):
self.printer = self.moo
self.printer()
def moo(self):
print("Y u printing?")
test = Test()
test.foo()
输出:
$ python test.py
Y u printing?
我知道规则是较早定义的,不是更高的,但是在这种情况下,它们都不是。
最佳答案
这里真的没有什么可混淆的。
我们有一个函数说:“当您使用foo
参数调用self
时,在moo
的命名空间中查找self
,将该值分配给printer
的命名空间中的self
,查找printer
的名称空间中的self
,并调用该值” .1
除非/直到您调用该函数,否则任何地方的任何人是否都具有名为moo
的属性都没有关系。
当您调用该方法时,作为self
传递的任何内容最好都具有moo
属性,否则您将获得AttributeError
。但这与在任何对象上查找属性没有什么不同。如果将def spam(n): return n.bit_length()
编写为全局函数,则在调用该函数时,作为n
传递的任何内容最好都具有bit_length
属性,否则将获得AttributeError
。
因此,我们将其称为test.foo()
,因此将test
传递为self
。如果您知道属性查找的工作方式(关于SO的问题和答案已经很多),则可以进行追溯。略为简化:test.__dict__
是否有'moo'
?没有。type(test).__dict__
是否有'moo'
?是。至此就完成了。
同样,这与我们检查3
是否具有bit_length()
方法的方法相同;这里没有多余的魔法。
这就是全部。
特别要注意,test.__dict__
没有'moo'
。方法在构造时(__new__
)的创建要比在初始化时(__init__
)的创建多。该实例中没有任何方法,因为它没有必须;他们可以在类型上查找2。
当然,我们可以深入了解描述符,方法解析顺序和object.__getattribute__
,以及如何编译和执行class
和def
语句,并进行特殊的方法查找以查看是否有自定义的__getattribute__
,依此类推。 ,但您不需要任何其他内容即可理解此问题。
1.如果对此感到困惑,那可能是因为您在考虑使用半面向对象语言(例如C ++及其后代),在该类中,类必须指定其所有实例的属性和方法,以便编译器可以查找在this->moo()
上计算出this has a static type of
Foo , work out that
moo is the third method defined on
Foo , and compile it into something like
this-> vptr2`。如果那是您所期望的,那么请忘记所有。在Python中,方法只是属性,而属性只是按需查找名称。
2.如果您要问“那为什么绑定方法和函数为什么不一样?”,答案就是描述符。简要地说:当在类型上找到属性时,Python调用值的__get__
方法,并将其传递给实例,而函数对象的__get__
方法返回方法对象。因此,如果要专门引用绑定的方法对象,则每次查找方法时都会创建它们。特别是,当我们调用foo
时,绑定的方法对象尚不存在。它是通过在self.moo
中查找foo
创建的。
关于python - 为什么此代码未引发“未定义”错误?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51423517/