2017-05-19 62 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()