2011-08-19 53 views
1

我是Python的新手,來自Perl世界。在python中使類數據可繼承的正確方法是什麼?

我想確定什麼是有關存儲和訪問類數據的最佳做法,以便它可以被繼承並可能由子類擴展。閱讀Python 2.7文檔(我實際上堅持使用2.6),潛入Python和過去的問題,這個問題的答案並不清楚。

在Python中的僞代碼類似...

class baseClass: 
    'DataMap' = { 
     'key1': 'val1', 
     'key2': 'val2', 
     'key3': 'val2', 
    } 

class subClass1(baseClass): # has access to DataMap 
    def myfunc: 
     ... 
     if DataMap[x] == 'val2': 
      print 'foo' # if x equals 'key2' according to the data map 
     y = DataMap['key4'] # error! 
     ... 

class subClass2(baseClass): # appends values to base DataMap 
    DataMap['key4'] = 'val4' 
    def myfunc: 
     ... 
     if DataMap[x] == 'val4': 
      print 'foo' # if x equals 'key4' according to the data map 
     elif DataMap[x] == 'val2': 
      print 'bar' # if x equals 'key2' according to the data map 
     ... 

我上面寫的是在直接一流的數據訪問有點頭腦的Perl是普遍的,主要是鼓勵,因爲開銷調用的方法。我感覺這種方法雖然不是很pythonic,但我想要一個理智的檢查。

應該DataMap,雖然不可變的一旦編譯,駐留在一個類函數,其中subClass1將通過類方法獲得該數據時,繼承baseClass和subClass2可以重寫相同的方法來追加/合併其數據映射與基地?

您的見解和智慧是值得讚賞的。

回答

2

大家知道,使用像dict這樣的可變對象作爲默認參數或者像__init__方法之類的東西可能不會像您認爲的那樣行爲。

舉個簡單的例子:

class A(object): 
    a = {'foo':1} 

a = A() 
a.a['bar'] = 2 

b = A() 
print b.a 

所以,現在b.a{'foo': 1, 'bar': 2},即使你希望它只是{'foo':1}

出於這個原因,它是共同把裏面的類的可變數據__init__功能。例如。

class A(object): 
    def __init__(self): 
     self.a = {'foo':1} 

a = A() 
a.a['bar'] = 2 

b = A() 
print b.a 
+0

是的,你的第一個例子並不如我想象的工作。我正在尋找具有該類所有對象共享的不可變數據集。你的第二個例子是爲每個對象實例創建一個不需要的數據副本。 – tima

2

如果定義:

class baseClass: 
    DataMap = { 
     'key1': 'val1', 
     'key2': 'val2', 
     'key3': 'val2', 
    } 

然後baseClass.__dict__包含'DataMap': {'key3': 'val2', 'key2': 'val2', 'key1': 'val1'}

這使得它不可能涉及DataMap是類繼承,因爲如果以後定義

class subClass2(baseClass): # appends values to base DataMap 
    DataMap = {'key4':'val4'} 

然後subClass2.__dict__有鍵'DataMap'自身的競爭條目。 如果s = subClass2()subClass2的一個實例,那麼s.DataMap將只訪問,subClass2.__dict__,一旦找到它,將永遠不會查找baseClass.__dict__。所以不會發生繼承。

您可以修改subClass2中的baseClass.__dict__,但由於子類不應修改其父項,因此違反了OOP原則。而且這不會是繼承,因爲對baseClass.__dict__的更改將影響baseClass的所有實例以及使用其DataMap的所有子類。


也許你可以實現你通過繼承DataMap自身找什麼:

class DataMap(object): 
    key1='val1' 
    key2='val2' 
    key3='val2' 

class subDataMap(DataMap): 
    key4='val4' 

class baseClass(object): 
    dataMap=DataMap 

class subClass1(baseClass): 
    def myfunc(self,x): 
     val=getattr(self.dataMap,x) 
     if val == 'val2': 
      print 'foo' 

class subClass2(baseClass): 
    dataMap=subDataMap 
    def myfunc(self,x): 
     val=getattr(self.dataMap,x) 
     if val == 'val4': 
      print 'foo' 
     elif val == 'val2': 
      print 'bar' 

s=subClass1() 
s.myfunc('key2') 
# foo 
try: 
    s.myfunc('key4') 
except AttributeError as err: 
    print(err) 
    # subClass1 instance has no attribute 'key4' 

s2=subClass2() 
s2.myfunc('key2') 
# bar 
s2.myfunc('key4') 
# foo 
+1

我在示例中顯示了一個DataMap,但在所有實際情況中,我正在查看幾個數據映射,以實現各種目的,這些映射應該由所有對象共享。我認爲這個解決方案會在我的「真實世界」下變得混亂嗎? – tima

+0

@tima:True;它會變得混亂。在這種情況下,爲了使用類屬性並獲得繼承的好處,我認爲最好將'DataMap'作爲一個類,並通過繼承'DataMap'來爲數據映射添加新的鍵值。 – unutbu

相關問題