Проблема с глубокой копией?

Источник

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']

Вопрос

Почему это выводит это? Я думал, что клонировал список ошибок перед его изменением, и что они не должны ссылаться на один и тот же список?

2 ответа

Решение

Установив dictfields в metaclassвы создаете атрибут класса.

__new__ определенный вами метод запускается только один раз - при создании класса.

Обновить

Вы должны манипулировать attrs в __new__ как вы, но назовите это как _fields, Затем создайте __init__ метод, который выполняет deepcopy в attribute называется fields,

Более явное решение:

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 создается экземпляр.

Другие вопросы по тегам