djo
djo

Reputation: 23

Prevent allocating a copy of an object when constructing a pydantic object

I'm trying to construct a sequence of pydantic objects which all have one attribute set to a specific single instanciated value, but when doing that, the pydantic constructor always allocates a copy of the instance to each object. Is there a way to prevent that behaviour?

Example:

from abc import ABC
from pydantic import BaseModel

class Solver(BaseModel):
    pass
class MyClass(Solver):
    chain: tuple | None = None

class AttributeClass(Solver):
    myvar: float | None = None

class System(ABC):
    solver = None
    
one_var = 1
chain =[AttributeClass(myvar=one_var) for _ in range(1,5)]    

class MySystem(System):
    solver = MyClass(chain=chain)

if __name__ == "__main__":

    my_instance = MySystem()

    print("original ID: ", id(one_var))

    for i,s in enumerate(my_instance.solver.chain):
        print(f"ID n° {i+1}: {id(s.myvar)}")

Here I would like all the elements in my_instance.solver.chain to have their attributes myvar set to one_var and not to a copy of it.

I have tried to add a Config class inside my AttributeClass and tried several options including copy_on_model_validation = False, but none did the trick.

Configurations: python 3.11 and pydantic 1.10 (I have the same issue with 2.4)

Upvotes: 2

Views: 325

Answers (1)

Michael H
Michael H

Reputation: 572

My Answer

Please refer to the examples below.

My Example

from pydantic import BaseModel

ONE_STRING = "foo"


class AttributeClass(BaseModel):
    mystring: str


class MyClass(BaseModel):
    attr: tuple[AttributeClass, ...]


if __name__ == "__main__":
    print(f'{id(ONE_STRING) = }')
    # > id(ONE_STRING) = 4334687984

    # [1] Use `ONE_STRING`
    my_instance = MyClass(
        attr=tuple(AttributeClass(mystring=ONE_STRING) for _ in range(1, 5))
    )
    for i, s in enumerate(my_instance.attr):
        print(f"mystring ID n° {i}: {id(s.mystring)}")
    # > mystring ID n° 0: 4334687984
    # > mystring ID n° 1: 4334687984
    # > mystring ID n° 2: 4334687984
    # > mystring ID n° 3: 4334687984

    # [2] `attr` object <- same instance
    my_attr_cls = AttributeClass(mystring=ONE_STRING)
    my_instance_2 = MyClass(attr=tuple(my_attr_cls for _ in range(1, 5)))
    for i, s in enumerate(my_instance_2.attr):
        print(f"attr ID n° {i}: {id(s)}")
    # > attr ID n° 0: 4354609296
    # > attr ID n° 1: 4354609296
    # > attr ID n° 2: 4354609296
    # > attr ID n° 3: 4354609296

Upvotes: 0

Related Questions