[英]Why is this code not throwing a 'not defined' error?
我创建了一些测试代码,但我无法真正理解它为什么起作用。
在使用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上is the third method defined on
, and compile it into something like
this-> vptr2`的形式。 如果那是您所期望的,那么请忘记所有。 在Python中,方法只是属性,而属性只是按需查找名称。
2.如果您要问“那为什么绑定方法和函数为什么不一样?”,答案就是描述符。 简要地说:当在类型上找到属性时,Python调用值的__get__
方法,将其传递给实例,而函数对象的__get__
方法返回方法对象。 因此,如果要专门引用绑定的方法对象,则每次查找方法时都会创建它们。 特别是,当我们调用foo
时,绑定方法对象尚不存在。 它是通过在foo
查找self.moo
创建的。
虽然@scharette所说的一切可能都是正确的(我对Python的内部知识了解不足,不足以表示信心:)),但我想提出一个替代的解释,说明为什么可以实例化Test
并调用foo()
:
在实际调用该方法之前,不会执行该方法的主体。 foo()
包含对未定义属性的引用都没有关系,它将被很好地解析。 只要在调用foo
之前创建moo
,就可以。
尝试在解释器中输入截断的Test
类:
class Test():
def __init__(self):
self.printer = None
def foo(self):
self.printer = self.moo
self.printer()
没有moo
,所以我们得到这个:
>>> test = Test()
>>> test.foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in foo
让我们现在将moo
添加到类中 :
>>> def moo(self):
... print("Y u printing?")
...
>>> Test.moo = moo
>>> test1 = Test()
>>> test1.foo()
Y u printing?
>>>
另外,您可以将moo
直接添加到实例 :
>>> def moo():
... print("Y u printing?")
...
>>> test.moo = moo
>>> test.foo()
Y u printing?
唯一的区别是实例的moo
不具有self
(请参阅此处以获取解释)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.