Problem with deepcopy?
Source
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
Output
['error msg']
Question
Why does it output that? I thought I cloned the errors list before modifying it, and that they shouldn't both refer to the sa开发者_JS百科me list?
By setting the dict
fields
in the metaclass
, you are creating a class attribute.
The __new__
method you defined is only run once -- on class creation.
Update
You should manipulate attrs
in __new__
like you are, but name it something like _fields
. Then create an __init__
method that performs a deepcopy
into an attribute
called fields
.
A more explicit solution:
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
Just moved the deepcopy
into BaseForm.__init__
instead, which actually is called each time a MyForm
is instantiated.
精彩评论