为什么不能通过副本传递实例的属性?我想将 name
属性传递给另一个数据框。
import copy
df = pd.DataFrame([1,2,3])
df.name = 'sheet1'
df2 = copy.deepcopy(df)
print(f'df.name: {df.name}')
>> df.name: sheet1
print(f'df2.name: {df2.name}')
>> AttributeError
...
'DataFrame' object has no attribute 'name'
同样,为什么这在创建类并从中继承时也不起作用?
class DfWithName(pd.DataFrame):
def __init__(self, *args, **kwargs):
self.__init__ = super().__init__(*args, **kwargs)
print('lol')
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value
并使用相同的代码:
import copy
df = DfWithName([1,2,3])
df.name = 'sheet1'
df2 = copy.deepcopy(df)
print(f'df.name: {df2.name}')
>> AttributeError
...
'DataFrame' object has no attribute 'name'
最佳答案
如别处所述,DataFrame
类有一个自定义的 __deepcopy__
与普通对象一样,该方法不一定复制分配给实例的任意属性。
有趣的是,有一个内部_metadata
属性似乎旨在能够列出复制/序列化时应保留的NDFrame
的其他属性。此处对此进行了一些讨论:https://github.com/pandas-dev/pandas/issues/9317
不幸的是,这仍然被认为是一个未记录的内部细节,所以它可能不应该被使用。通过查看代码,您原则上可以执行以下操作:
mydf = pd.DataFrame(...)
mydf.name = 'foo'
mydf._metadata += ['name']
当您复制它时,它应该带有名称。
您可以子类化 DataFrame
以使其成为默认值:
import functools
class NamedDataFrame(pd.DataFrame):
_metadata = pd.DataFrame._metadata + ['name']
def __init__(self, name, *args, **kwargs):
self.name = name
super().__init__(*args, **kwargs)
@property
def _constructor(self):
return functools.partial(self.__class__, self.name)
如果您为现有的 copy
方法提供自己的包装器,并且可能还有 __getstate__
和 __setstate__
。
更新:似乎实际上使用 _metadata
属性来扩展 Pandas 类现在是 documented .所以上面的例子应该或多或少起作用。这些文档更多地用于 Pandas 本身的开发,因此它可能仍然有点不稳定。但这就是 Pandas 本身扩展 NDFrame
子类的方式。
关于python - 为什么复制 Pandas DataFrame 后属性丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50372509/