Проблема с глубокой копией?
Источник
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 ответа
Решение
Установив dict
fields
в 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
создается экземпляр.