我创建了一些测试代码,但我无法真正理解它为什么起作用。

在使用前不应该定义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__,以及如何编译和执行classdef语句,并进行特殊的方法查找以查看是否有自定义的__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/

10-12 20:22