Skip to content
Advertisement

Python: Reassigning Object to Class with No Constructor Does Not Overwrite Dictionary Field

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 = {}
Advertisement