深拷贝出现问题?

4

来源

from copy import deepcopy

class Field(object):
    def __init__(self):
        self.errors = []

class BaseForm(object):
    pass

class MetaForm(type):
    def __new__(cls, name, bases, attrs):
        attrs['fields'] = dict([(name, deepcopy(attrs.pop(name))) for name, obj in attrs.items() if isinstance(obj, Field)])
        return type.__new__(cls, name, bases, attrs)

class Form(BaseForm):
    __metaclass__ = MetaForm

class MyForm(Form):
    field1 = Field()

f1 = MyForm()
f1.fields['field1'].errors += ['error msg']

f2 = MyForm()
print f2.fields['field1'].errors

输出

['error msg']

问题

为什么会输出这个?我以为在修改之前已经克隆了错误列表,并且它们不应该引用同一个列表?


看起来 MetaForm.__new__ 只被 MyForm(以及 Form)调用了 一次,尽管我构造了 两个 MyForms。这是怎么工作的?我的理解是每次构造时都需要调用它。我猜它在类级别上运行?那么最好把 deepcopy 语句放在哪里呢? - mpen
2个回答

2

通过在元类中设置dict fields,您正在创建一个类属性。

您定义的__new__方法只运行一次——在类创建时运行。

更新

您应该像现在这样在__new__中操作attrs,但将其命名为_fields之类的名称。然后创建一个__init__方法,执行deepcopy到名为fieldsattribute中。


啊..我猜我对__new__的工作原理有一个基本的误解。 - mpen
在哪个类上有一个 __init__?是 BaseForm 吗?因为 MetaForm.__init__ 也只被调用一次,不是吗? - mpen
Form类的__init__方法 - Zach
好的... Form 类被故意留空,所以我会把它放在基类里面。没什么区别。谢谢! - mpen

0
一个更明确的解决方案:
from copy import deepcopy

class Field(object):
    def __init__(self):
        self.errors = []

class BaseForm(object):
    def __init__(self):
        self.fields = deepcopy(self.fields)

class MetaForm(type):
    def __new__(cls, name, bases, attrs):
        attrs['fields'] = dict([(name, attrs.pop(name)) for name, obj in attrs.items() if isinstance(obj, Field)])
        return type.__new__(cls, name, bases, attrs)

class Form(BaseForm):
    __metaclass__ = MetaForm

class MyForm(Form):
    field1 = Field()

f1 = MyForm()
f1.fields['field1'].errors += ['error msg']

f2 = MyForm()
print f2.fields['field1'].errors

刚刚将deepcopy移到了BaseForm.__init__中,因为每当实例化MyForm时,实际上就会调用它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接