我创建了一些测试代码,但我真的不明白它为什么起作用。
在使用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?
我知道规则是更早定义,而不是更高,但是在这种情况下,它们都不是。
答案 0 :(得分:3)
这里真的没有什么可混淆的。
我们有一个函数说:“当您使用foo
参数调用self
时,在moo
的命名空间中查找self
,并将该值分配给{{ 1}}在printer
的命名空间中,在self
的命名空间中查找printer
,并调用该值。” 1
除非/直到您调用该函数,否则任何地方的任何人是否都具有名为self
的属性都没关系。
当您执行调用该方法时,无论您作为moo
传递的内容最好具有self
属性,否则您将获得moo
。但这与在 any 对象上查找属性没有什么不同。如果您将AttributeError
编写为全局函数,则在调用该函数时,以def spam(n): return n.bit_length()
传递的内容最好具有n
属性,否则您将获得{{1 }}。
因此,我们将其称为bit_length
,因此将AttributeError
传递为test.foo()
。如果您知道属性查找的工作方式(关于SO的问题和答案已经很多),则可以进行追溯。略为简化:
test
是否有self
?不。test.__dict__
是否有'moo'
?是。我们完成了。再次,这与我们检查type(test).__dict__
是否具有'moo'
方法的方法相同;这里没有多余的魔法。
这就是全部。
尤其要注意,3
没有bit_length()
。方法在构造时(test.__dict__
)的创建比在初始化时('moo'
)的创建要多。该实例中没有任何方法,因为它没有必须;可以在类型上查找它们。 2
当然,我们可以了解描述符,方法解析顺序,__new__
,__init__
和object.__getattribute__
语句的编译和执行方式,以及特殊的方法查找以了解是否存在自定义class
,依此类推,但您无需使用任何一个即可理解此问题。
1。如果对此感到困惑,那可能是因为您正在考虑使用半面向对象语言(例如C ++及其后代),在该类中,类必须指定其所有实例的属性和方法,因此编译器可以查看{ {1}},计算出def
Foo __getattribute__
moo this->moo()
Foo this has a static type of
this-> vptr2`。如果那是您所期望的,那么请忘记所有。在Python中,方法只是属性,而属性只是按需查找名称。
2。如果您要问“那为什么绑定方法和函数为什么不一样?”,答案就是描述符。简要地说:当在类型上找到属性时,Python调用值的, work out that
方法,并将其传递给实例,而函数对象的is the third method defined on
方法则返回方法对象。因此,如果要专门引用绑定的方法对象,则每次查找方法时都会创建它们。特别是,当我们调用, and compile it into something like
时,绑定方法对象尚不存在。它是通过在__get__
内查找__get__
来创建的。
答案 1 :(得分:1)
虽然@scharette所说的所有内容都是正确的(我对Python的内部知识了解不足,不足以表示信心:)),但我想提出一个替代性的解释,说明为什么可以实例化Test
并致电foo()
:
该方法的主体直到您实际调用它之后才执行。 foo()
是否包含对未定义属性的引用并不重要,它将被很好地解析。只要在致电moo
之前创建foo
,就可以了。
尝试在解释器中输入截断的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
(有关解释,请参见here)。