2012-07-20 61 views
4

在以下代碼:力蟒子類的init使用子類變量,而不是父類

class A(object): 
    VALUE = 1 
    def __init__(self, value=VALUE): 
    self.value = value 

class B(A): 
    VALUE = 2 

我期望B()值應等於2,但是:

B().value = 1 

有一種優雅的方式來定義一個類層次結構,其中子類可以只是聲明,他們希望重寫,並讓他們爲實例變量的默認值類變量?我仍然希望允許這些在每個實例級別上進行更改,例如。

b = B(value=3) 

回答

10

這是另一個default arguments的問題。重點是當你編寫的時候

def foo(value=VALUE): 

函數內部的代碼被編譯成一個函數對象。這是這個時間 - 不是在通話時! - 存儲默認參數。所以,你的時間已經確定B爲時已晚:中foo默認值已經被設置和改變VALUE不會有任何效果。

如果這似乎是一個奇怪的事情,假設foo是一個全球性的功能:

default = 3 
def foo(x=default): pass 

那麼任何其他代碼,任何地方,可以通過做

global default 
default = 4 

搞砸foo這無疑是同樣令人困惑。


要強制查找在運行時做了不編譯的時候,你需要把它們功能:

def foo(value=None): 
    self.value = self.VALUE if value is None else value 

或(不完全一樣,但是更漂亮)

self.value = value or self.VALUE 

(這是不同的,因爲它將把任何「falsy」值作爲前哨 - 也就是說,0[]{}等將全部由VALUE覆蓋)


編輯:@mgilson指出,這樣做的另一種方式:

def foo(**kwargs): 
    self.value = kwargs.get("value", self.VALUE) 

這是因爲它不要求整潔你做一個標記值(如Noneobject(),但它確實改變foo相當根本的參數規格,因爲現在它會接受任意關鍵字參數。你的來電。

+0

與津貼做正確的唯一方法:

可以按如下步驟寫出來。 – 2012-07-20 14:44:29

+3

@JonasWielicki:如果允許None,你可以使用一個哨兵NOT_VALUE = object()。你不需要'** kwargs' – jfs 2012-07-20 14:45:26

+0

@ J.F.Sebastian哦不錯。 – 2012-07-20 14:46:04

1

不應該在func聲明行中定義默認值,否則,當python讀取此行時,默認值將被重點關注,無論您稍後更改VALUE值,都不會更改默認值。對於`None`使用`** kwargs`雖然檢查中kwargs``「值」

class A: 
    VALUE = 1 
    def __init__(self, value=None): 
     if value is None: 
      value = self.VALUE 
     self.value = value 

class B(A): 
    VALUE = 2 

print(A().value) 
print(B().value) 
相關問題