2017-01-18 231 views
0

我想要創建一個新的超類實例(a.k.a.「parent」class)的方法。如何從該類的實例創建類的實例?

此外,我想子類上面描述的類,並有這個子類繼承該方法,然後能夠使用該方法創建自己的子類更多的實例。

但是,當我嘗試做這樣......

class Superclass: 
    def makeNew(self): 
     return self.__class__() #this isn't making a clean copy 

class Subclass(Superclass): 
    def __init__(self, value = [1]): 
     self.value = value 

    def setValue(self, newValue): 
     self.value[0] = newValue 

if __name__ == "__main__": 
    s = Subclass() 
    s.setValue(5) 
    other = s.makeNew() 
    print(s.value) 
    print(other.value) 

我得到

>>> [5] #s.value 
>>> [5] #other.value 

爲什麼不self.__class__()給我父的全新副本?

我在做什麼錯?我如何創建我想要的課程?

+0

你認爲什麼是「乾淨的副本」?你取而代之的是什麼?無論如何,這樣做的另一種方法是在子類中定義一個'@ staticmethod',它將創建並返回新的實例。如果's'是子類的一個實例(這就是你給靜態方法的名字),你可以用's.make_new_instance()'調用它。 – martineau

+0

「乾淨的拷貝」我的意思是它與原來的's'完全分開。它應該打印'[5] \ n [1]' –

回答

4

這不是你的makeNew方法的問題;這是您的__init__的問題。當你有一個可變的默認參數時,修改該值將修改你所有未來的默認值。你應該做的是這樣的:

def __init__(self, value=None): 
    if value is None: 
     value = [1] 
    # ... 

這樣,每個新的實例創建一個新的列表,而不是更多的引用到同一個列表。

在附註中,看起來並不需要value作爲列表。當然,其他代碼在這裏沒有顯示可能需要它,但如果這是所有的代碼,所有你需要的是self.value = ...。既然你現在重新指定self.value而不是修改它,你可以使用默認參數。

+0

好的!列表和字典對於默認參數幾乎總是一個壞主意。沒有解決方案是我最喜歡的,但如果它不需要有一個默認參數,可以簡單地將它完全放棄。 – Alan

+0

使用'makeNew'基類方法解決問題。當它調用'self .__ class __()'時,如果它的'self'參數被設置爲一個子類實例(如's.makeNew()'那樣)調用子類,如問題所示。 – martineau

+0

@martineau:我不知道爲什麼這是一個問題。如果在子類上調用'makeNew'給了你一個超類的實例,那麼我會調用那個期望的行爲,而不是一個問題。 – zondo