2017-05-19 61 views
4

我有一個實例變量,似乎被視爲類變量,因爲它更改了該對象的所有實例。Python似乎將實例變量視爲類變量

class DNA(object): 

     def __init__(self,genes = pd.DataFrame(), sizecontrol=500, name='1'): 
     self.name = name 
     self.genes = genes # This attribute should be an instance variable 
     self.GeneLen = self.genes.shape[1] 
     self.sizecontrol = sizecontrol 
     self.Features = [] 
     self.BaseFeats = [] 
     random.seed(self.name) 

當我運行此我得到如下:

In[68]: df = pd.DataFrame(data) 

In[69]: x1 = DNA(genes=df) 

In[70]: x2 = DNA(genes=df) 

In[71]: x1.genes["dummy"] = 'test' 

In[72]: x2.genes["dummy"].head(4) 
Out[72]: 
    0 test 
    1 test 
    2 test 
    3 test 

我怎樣才能確保x1.genes不影響x2.genes?

+1

嘗試傳遞df變量作爲'DNA(基因= df.copy())' – ZdaR

+0

您的兩個實例都使用與他們的'.genes'屬性相同的數據框。 –

+1

其中,@ PM2Ring意味着內存中的字面意思相同。 – timgeb

回答

5

這裏有兩個問題。

首先,數據框架是可變對象,並且您的兩個實例都引用同一個對象。您需要使用df.copy()向每個實例提供新副本。您可以選擇複製__init__函數本身的數據幀。這將是「更安全」的,因爲可以確保您不重複使用數據幀,但這也可能會產生不必要的副本。

其次,在您的示例中不相關,提供可變默認參數genes = pd.DataFrame()時出現問題。該數據幀保存在未綁定的__init__函數中,就像它是該函數的成員數據一樣(請參閱__init__.__func__.func_defaults)。相反,使用默認參數None或其他一些sentinel值,然後在genes is None時實例化新的數據幀。

+0

@ PM2Ring只是注意到並相應更新。 –

+0

「這個數據框被保存在類的類成員數據類的類」不完全,但我知道你的意思。只是當創建類定義本身時,默認參數纔會被計算一次。這就是爲什麼它會導致默認的可變參數問題。 –

+0

@SyrtisMajor這與OP的問題並不真正相關,因爲他們實際上並未使用該默認參數。但我完全同意,如果他們想在那裏使用默認值,他們應該使用'None'並在'__init__'的主體中測試'None' –

5

您的代碼工作正常,因爲genesDNA類的實例的屬性。

但是,您只創建了一個數據框。指定的名稱df給它,也讓它的屬性都x1x2genes

self.genes = genes 

分配。由於分配從未複製數據您仍然只有一個數據幀,它在x1x2之間共享。

enter image description here

爲了解決這個問題,你既可以讓你的數據幀的副本,將它傳遞給DNA構造函數之前或在__init__方法使用

self.genes = genes.copy()