Python 为什么复制数据帧后属性会丢失
为什么不可能通过副本传递实例的属性?我想将Python 为什么复制数据帧后属性会丢失,python,Python,为什么不可能通过副本传递实例的属性?我想将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 ...
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'
熊猫似乎不支持将自定义元数据附加到数据帧。请参阅(可能重复?)和。此代码工作:
>>> class test():
... @property
... def name(self):
... return self._name
... @name.setter
... def name(self, value):
... self._name = value
...
>>>
>>> a = test()
>>> a.name = 'Test123'
>>> import copy
>>> a2 = copy.deepcopy(a)
>>> print(a2.name)
Test123
所以我认为行为是由pd.DataFrame
我发现pandas定义了函数\uuuu deepcopy\uuuu
,但我不能完全理解原因
如果在MRO中找到,将使用自定义的\uuuu deepcopy\uuuu
方法,该方法可能会返回它喜欢的任何结果(包括完全虚假的结果)。事实上,数据帧实现了一种\uuuu deepcopy\uuu
方法:
def __deepcopy__(self, memo=None):
if memo is None:
memo = {}
return self.copy(deep=True)
它将委托给self.copy
,您将在其中找到:
您将在(合并在中)中找到:
\uuuuu deepcopy\uuuuuu
现在返回数据的浅拷贝(当前为视图)——允许更改元数据
相关问题:.如其他地方所述,
DataFrame
类有一个自定义方法,它不一定像普通对象那样复制分配给实例的任意属性
有趣的是,有一个内部的\u元数据
属性,它似乎可以列出复制/序列化NDFrame
时应保留的其他属性。这里讨论了这一点:
不幸的是,这仍然被认为是一个未记录的内部细节,所以它可能不应该被使用。通过查看代码,原则上您可以执行以下操作:
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
方法提供了自己的包装,并且可能还提供了\uuuuu getstate\uuuuuuu
和\uuuu setstate\uuuuu
,那么您也可以在不依赖此内部\uu metadata
属性的情况下执行此操作
更新:现在似乎已经开始使用
\u metadata
属性来扩展熊猫类了。因此,上面的例子应该或多或少起作用。这些文件更多的是为了熊猫本身的发展,所以它可能仍然有点不稳定。但熊猫本身就是这样扩展NDFrame
的子类的,也许我发现了一个错误的复制。。。关键是您的新属性只属于这个特定实例,它不记录在类级别。因此,copy
无法找到它@这并不完全准确。对于大多数实例,copy.deepcopy()
将复制其\uuuu dict\uuuu
成员,因此,如果将某些属性分配给实例,然后复制该实例,则将复制其属性。更可能的是,DataFrame
,作为一个相当普通的类,可能有一些自定义的序列化/深度复制实现,它不知道附加到它的任意属性。事实上,NDFrame
(它是DataFrame
的基类)有这个自定义的\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
:是的,更准确。您可以重写\uuuu deepcopy\uuuuu
,它只记录与类相关的信息并不奇怪。使用df.copy(deep=True)
也不能缓解问题。我现在知道元数据副本没有实现,但我想知道是什么python机制导致了这种情况。是的,使用\u metadata
属性hack非常适合我的用例。请注意我对示例代码的更新。我还没有测试过它,但我想你可能需要像上面的\u构造函数那样的东西。似乎你没有在第一个链接中链接答案,这与你后来链接的github问题相同。如果可以,请编辑您的答案,以包含相关的,可能是重复的答案。@JimFasarakisHilliard谢谢,已更新。虽然我很确定这不是重复,但OP的问题更具体
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)