繁体   English   中英

为什么此代码未引发“未定义”错误?

[英]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?

我知道规则是更早定义的 ,不是更高 定义的 ,但是在这种情况下,它们都不是。

这里真的没有什么可混淆的。

我们,说:“当你调用一个函数fooself参数,查找mooself的命名空间,该值分配给printerself的命名空间,查找printerself的命名空间,称之为价值” 。 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__ ,以及如何编译和执行classdef语句,并可以进行特殊的方法查找以查看是否有自定义的__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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM