Consider the following class:
from dataclasses import dataclass
@dataclass
class Test:
result: int = None
@dataclass
class Test2:
nested = Test()
result: int = None
class Mainthing:
def __init__(self, value):
self.value = value
self.results = Test2()
def Main(self):
value = self.value
self.results.result = value
self.results.nested.result = value
If I make an instance of the class:
x = Mainthing(1)
And call the Main() function:
x.Main()
The results are as they should be,
x.results.result
Out[0]: 1
x.results.nested.result
Out[1]: 1
If I then delete the instance
del x
and make it again
x = Mainthing(1)
The x.results.result is now None as i would expect, but the nested is not
x.results.nested.result
Out[]: 1
Why is that?
>Solution :
Without a type annotation, nested is a class attribute, unused by @dataclass, which means it’s shared between all instances of Test2 (dataclasses.fields(Test2) won’t report it, because it’s not an instance attribute).
Making it an instance attribute alone, with:
nested: Test = Test()
might seem like it works (it does make it a field), but it’s got the same problem using mutable default arguments has everywhere; it ends up being a shared default, and mutations applied through one instance change the value shared with everyone else.
If you want to use a new Test() for each instance, make it a field with a default_factory, adding field to the imports from dataclasses, and changing the definition to, e.g.:
nested: Test = field(default_factory=Test)
If you always want to create your own instance, never accept one from the user, make it:
nested: Test = field(default_factory=Test, init=False)
so the generated __init__ does not accept it (accepting only result).