Bre*_*ode 82 python python-internals
所以只是为了建立,我觉得我理解复制模块中的copyvs 之间的区别deepcopy,我已经使用过copy.copy并且copy.deepcopy成功之前,但这是我第一次真正去重载__copy__和__deepcopy__方法.我已经围绕谷歌搜索,并通过看内置的Python模块查找的实例__copy__和__deepcopy__功能(例如sets.py,decimal.py和fractions.py),但我仍然肯定不是100%我已经得到了它的权利.
这是我的情景:
我有一个配置对象,它主要由简单属性组成(尽管它可能包含其他非基本对象的列表).最初,我将使用一组默认值来实例化一个配置对象.此配置将切换到多个其他对象(以确保所有对象以相同的配置启动).然而,一旦用户交互开始,每个对象将需要能够独立地调整配置而不影响彼此的配置(对我来说,我需要使用我的初始配置的深度复制来处理).
这是一个示例对象:
class ChartConfig(object):
def __init__(self):
#Drawing properties (Booleans/strings)
self.antialiased = None
self.plot_style = None
self.plot_title = None
self.autoscale = None
#X axis properties (strings/ints)
self.xaxis_title = None
self.xaxis_tick_rotation = None
self.xaxis_tick_align = None
#Y axis properties (strings/ints)
self.yaxis_title = None
self.yaxis_tick_rotation = None
self.yaxis_tick_align = None
#A list of non-primitive objects
self.trace_configs = []
def __copy__(self):
pass
def __deepcopy__(self, memo):
pass
Run Code Online (Sandbox Code Playgroud)
在这个对象上实现copy和deepcopy方法的正确方法是什么,以确保copy.copy并copy.deepcopy给我正确的行为?我目前正在使用Python 2.6.2.
提前致谢!
Ant*_*ins 82
将Alex Martelli的答案和Rob Young的评论放在一起,您将获得以下代码:
from copy import copy, deepcopy
class A(object):
def __init__(self):
print 'init'
self.v = 10
self.z = [2,3,4]
def __copy__(self):
cls = self.__class__
result = cls.__new__(cls)
result.__dict__.update(self.__dict__)
return result
def __deepcopy__(self, memo):
cls = self.__class__
result = cls.__new__(cls)
memo[id(self)] = result
for k, v in self.__dict__.items():
setattr(result, k, deepcopy(v, memo))
return result
a = A()
a.v = 11
b1, b2 = copy(a), deepcopy(a)
a.v = 12
a.z.append(5)
print b1.v, b1.z
print b2.v, b2.z
Run Code Online (Sandbox Code Playgroud)
版画
init
11 [2, 3, 4, 5]
11 [2, 3, 4]
Run Code Online (Sandbox Code Playgroud)
这里__deepcopy__填写memodict以避免在对象本身从其成员引用的情况下进行过多复制.
Ale*_*lli 68
自定义的建议位于文档页面的最后:
类可以使用相同的接口来控制用于控制酸洗的复制.有关这些方法的信息,请参阅模块pickle的说明.复制模块不使用copy_reg注册模块.
为了让类定义自己的副本实现,它可以定义特殊的方法
__copy__()和__deepcopy__().前者被称为实现浅拷贝操作; 没有传递其他参数.调用后者来实现深拷贝操作; 它传递了一个参数,即备忘录字典.如果__deepcopy__()实现需要对组件进行深层复制,则应该deepcopy()以组件作为第一个参数并将备注字典作为第二个参数来调用该函数.
既然您似乎不关心酸洗定制,那么定义__copy__并且__deepcopy__绝对是正确的方式.
具体来说,__copy__(浅拷贝)在你的情况下很容易......:
def __copy__(self):
newone = type(self)()
newone.__dict__.update(self.__dict__)
return newone
Run Code Online (Sandbox Code Playgroud)
__deepcopy__也是类似的(接受memoarg)但在返回之前它必须调用self.foo = deepcopy(self.foo, memo)任何self.foo需要深度复制的属性(本质上是容器的属性 - 列表,dicts,非原始对象,通过它们保存其他东西__dict__).
Ein*_*din 13
遵循Peter的出色答案,实现自定义深度复制,对默认实现进行最小的更改(例如,只修改我需要的字段):
class Foo(object):
def __deepcopy__(self, memo):
deepcopy_method = self.__deepcopy__
self.__deepcopy__ = None
cp = deepcopy(self, memo)
self.__deepcopy__ = deepcopy_method
# custom treatments
# for instance: cp.id = None
return cp
Run Code Online (Sandbox Code Playgroud)
我可能会对细节有所了解,但是这里有所作为;
来自copy文档 ;
- 浅拷贝构造一个新的复合对象,然后(尽可能)将对它的引用插入到原始对象中.
- 深层复制构造一个新的复合对象,然后递归地将复制对象插入到原始对象中找到的对象中.
换句话说:copy()将仅复制顶部元素,并将其余元素作为指向原始结构的指针.deepcopy()将以递归方式复制所有内容.
那就是deepcopy()你需要的.
如果您需要做一些非常具体的事情,您可以覆盖__copy__()或__deepcopy__(),如手册中所述.就个人而言,我可能会实现一个普通函数(例如config.copy_config()或类似函数)来说明它不是Python标准行为.
从您的问题中不清楚为什么需要覆盖这些方法,因为您不希望对复制方法进行任何自定义.
无论如何,如果您确实想要自定义深层副本(例如,通过共享某些属性并复制其他属性),这里有一个解决方案:
from copy import deepcopy
def deepcopy_with_sharing(obj, shared_attribute_names, memo=None):
'''
Deepcopy an object, except for a given list of attributes, which should
be shared between the original object and its copy.
obj is some object
shared_attribute_names: A list of strings identifying the attributes that
should be shared between the original and its copy.
memo is the dictionary passed into __deepcopy__. Ignore this argument if
not calling from within __deepcopy__.
'''
assert isinstance(shared_attribute_names, (list, tuple))
shared_attributes = {k: getattr(obj, k) for k in shared_attribute_names}
if hasattr(obj, '__deepcopy__'):
# Do hack to prevent infinite recursion in call to deepcopy
deepcopy_method = obj.__deepcopy__
obj.__deepcopy__ = None
for attr in shared_attribute_names:
del obj.__dict__[attr]
clone = deepcopy(obj)
for attr, val in shared_attributes.iteritems():
setattr(obj, attr, val)
setattr(clone, attr, val)
if hasattr(obj, '__deepcopy__'):
# Undo hack
obj.__deepcopy__ = deepcopy_method
del clone.__deepcopy__
return clone
class A(object):
def __init__(self):
self.copy_me = []
self.share_me = []
def __deepcopy__(self, memo):
return deepcopy_with_sharing(self, shared_attribute_names = ['share_me'], memo=memo)
a = A()
b = deepcopy(a)
assert a.copy_me is not b.copy_me
assert a.share_me is b.share_me
c = deepcopy(b)
assert c.copy_me is not b.copy_me
assert c.share_me is b.share_me
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
48257 次 |
| 最近记录: |