2017-09-12 51 views
1

當我在類代碼塊中使用任何類變量時,我得到未定義的錯誤。我該如何解決它?Python爲什麼我沒有定義錯誤?

例如

class A(): 
    __hidden_number__ = 5 
    __no_hidden_number__ = A.__hidden_number__ + 4 # to cause error. why ? 

感謝。

+1

嘗試'__no_hidden_​​number__ = __hidden_​​number__ + 4' –

+0

因爲'A'尚未定義。 –

+1

@ juanpa.arrivillaga nope。你在'A'範圍內。你指的是'A.A'。檢查我的答案並測試片段。 –

回答

4

你的類變量已經在A命名空間中。

所以,你只需要做:

__no_hidden_number__ = __hidden_number__ + 4 

否則你試圖訪問A.A,它還不存在。

爲了說明什麼,我指出,該「工程」(而不是你想要的):

class A(): 
    class A(): 
     __hidden_number__ = 4 
    __no_hidden_number__ = A.__hidden_number__ + 4 
A() # that works 

認爲不會:

class A(): 
    class B(): 
     __hidden_number__ = 4 
    __no_hidden_number__ = A.__hidden_number__ + 4 # B.__... would've worked 
A() # beeep: NameError: name 'A' is not defined 

注意,你應該避免定義帶有雙下劃線的私人屬性(__xxx__)。它可以工作,但這通常是爲python特殊類成員(__class____file____eq__等)保留的。名稱修改(使對象成爲「私有」)已經以2個前導下劃線出現。

+1

注意問題是*爲什麼*錯誤出現。那麼'A'在類聲明完成之前沒有定義。 – dhke

+0

@ Jean-FrançoisFabreErm?是?名稱'A'在類聲明後嚴格分配。 – dhke

+0

嘗試我的代碼片段,然後通過'B'更改內部'A',看看會發生什麼 –

2

由於這可能是一個有點不清楚(現有的答案是罰款),讓我補充到:

class A: 
    pass 

is equivalent to

A = type('A', (object,), {}) 

我們寫的類聲明裏面有什麼本質上是建立(這裏是空的)字典,並且發生之前變量A被分配。而且,由於我們還沒有 - 名稱空間層次結構中名稱爲A的變量,而類聲明運行時,A不可用。

的類存在,它也有類型名稱'A',但目前還沒有得到賦值給變量A,但。

class A: pass -version和明確type調用之間的區別是語法糖:使用class,一切都嵌套在類中被自動命名空間到類字典。

這就是爲什麼這個工程:

class A: 
    var = 1 
    var2 = var + 1 

但我們可以在上面看到,局部變量A,將最終持有類的聲明已經被評估後,才我們的新類被分配,因此ISN」 t可用於其內部。

如果我們拆開一類DECL,我們得到:

import codeop, dis 
    dis.disassemble(codeop.compile_command('class A:\r\n pass')) 

1   0 LOAD_CONST    0 ('A') 
      3 LOAD_CONST    3 (()) 
      6 LOAD_CONST    1 (<code object A at 0x80076ff30, file "<input>", line 1>) 
      9 MAKE_FUNCTION   0 
      12 CALL_FUNCTION   0 
      15 BUILD_CLASS   
      16 STORE_NAME    0 (A) 
      19 LOAD_CONST    2 (None) 
      22 RETURN_VALUE 

1922會自動添加,因爲代碼對象必須返回一個值。我們可以忽略這些例子。

這裏還發生了什麼?

  • 0:將字符串'A'推到堆棧上。這將成爲班級的名字(type()的第一個參數)。
  • 3:推一個空元組,母類的列表
  • 6:加載類聲明的代碼對象。
  • 912運行類聲明代碼對象。這是例如做我們的(類)變量分配。它返回類字典。
  • 15將該類構建到堆棧上。這相當於type('A',(), class_dict),其中參數恰好是堆棧中此時的值。

最後:

  • 16店剛創建的類到名稱A下的局部命名空間。

我們可以看到,在類聲明運行(12),前級分配給它的可變A16)。

請注意,在Python 3中反彙編是不同的,因爲python作爲特殊的內建函數class builder function

是的,這是一個太長的答案;-)。

+0

現在我明白了。這只是因爲它正在構建中而不能成爲相同的「A」。所以我們都是對的。你的回答是我忽略的一個很好的附加組件。 –

+0

@ Jean-FrançoisFabre我並不是想說你錯了,但細節有點討厭。 Python是一個堆棧機器,區分「堆棧中的類型對象」A''和「名稱爲'A的變量來保存該類型對象」在這裏有所不同。 – dhke

相關問題