Repository: marshmallow-code/marshmallow

Issue:
Root reference is broken for nested/container fields when using schema inheritance 
I use schema inheritance a lot to reuse shared parts of schemas. Additionally I have some custom fields with validation methods which use references to the field's root schema. When these custom fields are used in nested schemas or inside lists, then the same field instance is used in different schema classes and thus the root reference is "broken":

```python
>>> import marshmallow
>>> marshmallow.__version__
'3.0.0b13'
>>> from marshmallow import fields
>>> from marshmallow.schema import Schema
>>> class A(Schema):
...     f1 = fields.List(fields.Integer())
... 
>>> class B(A):
...     pass
... 
>>> a = A()
>>> b = B()
>>> a_f1 = a.declared_fields['f1']
>>> b_f1 = b.declared_fields['f1']
>>> a_f1.root == a
True
>>> b_f1.root == b
True
>>> a_f1.container.root == a
False
>>> a_f1.container.root == b
True
```
So the problem is that the container root of field `f1` of schema instance `a` is schema instance `b`. In fact `a_f1.container` and `b_f1.container` point to the same object.

Is this a problem of how I use marshmallow or is this a bug?

I find the possibility to reference a field's root schema very valuable and the root property looks like it can be used like that. However, I think the problem here is that nested (or container) fields are not unique instances when used in multiple classes.

Discussion:

Patch:
diff --git a/marshmallow/fields.py b/marshmallow/fields.py
index b0580fd3..ea9b3efb 100755
--- a/marshmallow/fields.py
+++ b/marshmallow/fields.py
@@ -4,6 +4,7 @@
 from __future__ import absolute_import, unicode_literals
 
 import collections
+import copy
 import datetime as dt
 import numbers
 import uuid
@@ -568,6 +569,7 @@ class List(Field):
 
     def _add_to_schema(self, field_name, schema):
         super(List, self)._add_to_schema(field_name, schema)
+        self.container = copy.deepcopy(self.container)
         self.container.parent = self
         self.container.name = field_name
 
@@ -1207,9 +1209,11 @@ class Dict(Field):
     def _add_to_schema(self, field_name, schema):
         super(Dict, self)._add_to_schema(field_name, schema)
         if self.value_container:
+            self.value_container = copy.deepcopy(self.value_container)
             self.value_container.parent = self
             self.value_container.name = field_name
         if self.key_container:
+            self.key_container = copy.deepcopy(self.key_container)
             self.key_container.parent = self
             self.key_container.name = field_name
 


Test patch:
diff --git a/tests/test_fields.py b/tests/test_fields.py
index 15ce7562..e97c4249 100644
--- a/tests/test_fields.py
+++ b/tests/test_fields.py
@@ -129,6 +129,28 @@ class TestParentAndName:
     def test_list_field_inner_root(self, schema):
         assert schema.fields['bar'].container.root == schema
 
+    def test_list_root_inheritance(self, schema):
+        class OtherSchema(TestParentAndName.MySchema):
+            pass
+
+        schema2 = OtherSchema()
+        assert schema.fields['bar'].container.root == schema
+        assert schema2.fields['bar'].container.root == schema2
+
+    def test_dict_root_inheritance(self):
+        class MySchema(Schema):
+            foo = fields.Dict(keys=fields.Str(), values=fields.Int())
+
+        class OtherSchema(MySchema):
+            pass
+
+        schema = MySchema()
+        schema2 = OtherSchema()
+        assert schema.fields['foo'].key_container.root == schema
+        assert schema.fields['foo'].value_container.root == schema
+        assert schema2.fields['foo'].key_container.root == schema2
+        assert schema2.fields['foo'].value_container.root == schema2
+
 
 class TestMetadata: