簡體   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