I’m using Python 3.9.1
and am confused how Python’s default constructor works.
I have the below class with a Dictionary
field and no Constructor.
When I populate its Dictionary
and then reassign my object to a new instance, the dictionary retains its existing value (this also happens for List
fields):
from typing import Dict class MyClass: records: Dict[str, str] = {} if __name__ == '__main__': my_class = MyClass() print(my_class.records) # prints `{}`. my_class.records['1'] = 'one' print(my_class.records) # prints `{'1': 'one'}`. # This does not overwrite `my_class` with a new instance. # `records` still contains the above element. my_class = MyClass() print(my_class.records) # prints `{'1': 'one'}`.
However, when I add a constructor, it works as expected:
from typing import Dict class MyClass: records: Dict[str, str] = {} def __init__(self) -> None: self.records = {} if __name__ == '__main__': my_class = MyClass() print(my_class.records) # prints `{}`. my_class.records['1'] = 'one' print(my_class.records) # prints `{'1': 'one'}`. # `my_class` is now overwritten and `records` has been set to `{}`. my_class = MyClass() print(my_class.records) # prints `{}`
I was under the impression that Python’s default constructor would use the fields I have declared in the class (records: Dict[str, str] = {}
in this case) to overwrite the existing object.
What doubly confuses me is that when I work with a regular field (string
in the below case, but it also works for custom classes), I don’t need a constructor to overwrite the field:
class MyClass: field: str = '' if __name__ == '__main__': my_class = MyClass() print(my_class.field) # prints nothing. my_class.field = 'some value' print(my_class.field) # prints `some value`. # `field` has been reset to '' even though `MyClass` has no constructor. my_class = MyClass() print(my_class.field) # prints nothing.
Can someone explain what Python is doing?
Advertisement
Answer
Specifically, why is the dictionary field’s state being changed instead of it being overwritten?
Because you’re not assigning to records. You’re just reading it. This
my_class.records['1'] = 'one'
is equivalent to this
d = my_class.records d['1'] = 'one'
Also, this is why adding that constructor makes the code “work”. Because in it, you’re reassigning records
.
self.records = {}