Repository: pydantic/pydantic

Issue:
Nested basemodel contain different instances of child models in a collection than origially provided. 
# Question
I wanted to use an ID based hashing for `BaseModel` instances. It appears to be the case that nested base models create  new objects in a hashable collection like `set`  or a mutable collection like `List`. 

Output of `python -c "import pydantic.utils; print(pydantic.utils.version_info())"`:
```
           pydantic version: 1.6.1
           pydantic compiled: True
           install path: /home/umesh/personal/pydantic/pydantic
           python version: 3.7.8 | packaged by conda-forge | (default, Jul 31 2020, 02:25:08)  [GCC 7.5.0]
           platform: Linux-5.0.0-32-generic-x86_64-with-debian-buster-sid
           optional deps. installed: ['typing-extensions', 'email-validator', 'devtools']
```
 In this snippet (grabbed from FastAPI examples). Class  `Item` has a list of `Images`, which adhere to equality based on `id `. It appears to be the case that instance variable `images`  of `Item`  contain images are different from the ones originally provided from the constructor. Is there a way to skirt that? 

```py
from pydantic import BaseModel
from typing import List, Set, Optional


class Image(BaseModel):
    url: str
    name: str

    def __hash__(self):
        return id(self)

    def __eq__(self, other):
        return self is other


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = []
    images: Optional[List[Image]] = None


image_1 = Image(url='https://s3.amazon-aws.com/dakl/kals', name='profile_pic_1.png')
image_2 = Image(url='https://s3.amazon-aws.com/dakl/kals', name='profile_pic_1.png')

item = Item(name='my_item1', price=0.050, images={image_1, image_2})
print(image_1 in item.images)

print(id(image_1), id(item.images[0]), id(image_2), id(item.images[1]))
```
Output:
```
139644562343408 139644562344208 139644562343328 139644562344368
```


Comments:
Hello @umesh-timalsina 
This is a known "issue", which may or may not be changed in v2. It reminds me of #265, which could help you. I'm currently not with my computer sorry
Hello @PrettyWood. Thanks for the response. I will check the issue out.

Patch:
diff --git a/docs/examples/model_config_change_globally_custom.py b/docs/examples/model_config_change_globally_custom.py
new file mode 100644
--- /dev/null
+++ b/docs/examples/model_config_change_globally_custom.py
@@ -0,0 +1,14 @@
+from pydantic import BaseModel as PydanticBaseModel
+
+
+class BaseModel(PydanticBaseModel):
+    class Config:
+        arbitrary_types_allowed = True
+
+
+class MyClass:
+    """A random class"""
+
+
+class Model(BaseModel):
+    x: MyClass
diff --git a/pydantic/main.py b/pydantic/main.py
--- a/pydantic/main.py
+++ b/pydantic/main.py
@@ -128,6 +128,9 @@ class BaseConfig:
     json_encoders: Dict[Type[Any], AnyCallable] = {}
     underscore_attrs_are_private: bool = False
 
+    # Whether or not inherited models as fields should be reconstructed as base model
+    copy_on_model_validation: bool = True
+
     @classmethod
     def get_field_info(cls, name: str) -> Dict[str, Any]:
         fields_value = cls.fields.get(name)
@@ -669,7 +672,7 @@ def validate(cls: Type['Model'], value: Any) -> 'Model':
         if isinstance(value, dict):
             return cls(**value)
         elif isinstance(value, cls):
-            return value.copy()
+            return value.copy() if cls.__config__.copy_on_model_validation else value
         elif cls.__config__.orm_mode:
             return cls.from_orm(value)
         elif cls.__custom_root_type__:


Test patch:
diff --git a/tests/test_main.py b/tests/test_main.py
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -1425,3 +1425,50 @@ class M(BaseModel):
         a: int
 
     get_type_hints(M.__config__)
+
+
+def test_inherited_model_field_copy():
+    """It should copy models used as fields by default"""
+
+    class Image(BaseModel):
+        path: str
+
+        def __hash__(self):
+            return id(self)
+
+    class Item(BaseModel):
+        images: List[Image]
+
+    image_1 = Image(path='my_image1.png')
+    image_2 = Image(path='my_image2.png')
+
+    item = Item(images={image_1, image_2})
+    assert image_1 in item.images
+
+    assert id(image_1) != id(item.images[0])
+    assert id(image_2) != id(item.images[1])
+
+
+def test_inherited_model_field_untouched():
+    """It should not copy models used as fields if explicitly asked"""
+
+    class Image(BaseModel):
+        path: str
+
+        def __hash__(self):
+            return id(self)
+
+        class Config:
+            copy_on_model_validation = False
+
+    class Item(BaseModel):
+        images: List[Image]
+
+    image_1 = Image(path='my_image1.png')
+    image_2 = Image(path='my_image2.png')
+
+    item = Item(images={image_1, image_2})
+    assert image_1 in item.images
+
+    assert id(image_1) == id(item.images[0])
+    assert id(image_2) == id(item.images[1])