1
class Animal:
    def __init__(self, name='', child=[]):
        self.name=name
        self.child=child

val = []


dog = Animal(name="Foo")
val.append(dog.__dict__)

cat = Animal(name='John')
cat.child.append('Doe')
val.append(cat.__dict__)

print(val)

Result:

[{'name': 'Foo', 'child': ['Doe']}, {'name': 'John', 'child': ['Doe']}]

Expected:

[{'name': 'Foo', 'child': []}, {'name': 'John', 'child': ['Doe']}]

I am assuming it's something to do with memory allocation but can't work around my head how it works.

vvvvv
  • 25,404
  • 19
  • 49
  • 81
wintan
  • 66
  • 1
  • 7

2 Answers2

0

dictionaries are reference type variables. A reference is a name that refers to the specific location in memory of a value (object). it means after you instantiate a dict it always point to the same location in memory. no matter if you edit your dict. so an easy solution to you code is:

class Animal:

    def __init__(self, name='', child=None):
        self.name=name
        self.child=child
        if self.child is None:
            self.child = []
    

val = []

dog = Animal(name="Foo")
print(dog.__dict__)
val.append(dog.__dict__)

cat = Animal(name='John')
cat.child.append('Doe')
val.append(cat.__dict__)

print(val)

this way every time you create an object from Animal class, it reserves a new place in memory.

  • "dictionaries are reference type variables" - this is a bit misleading. All Python names (variables if you like) are unidirectional references to some object in memory, no matter its datatype. It could be a list, int, dict, ... does not matter to the name. What you probably meant to say: "dicts are mutable". – timgeb Dec 16 '21 at 11:00
  • @timgeb yes that's completely true. dict is mutable and you must be fully understand how python thinks and acts on "mutable". the easy way to demonstrate that is that it is something exists on the memory and every time you are referring to the same place. – Mohsen Hashemi Dec 16 '21 at 11:09
0

You can use dataclasses and set the default factory for lists

from dataclasses import dataclass, field, asdict
from typing import List

@dataclass
class Animal:
    name : str 
    children : List[str] = field(default_factory=list)

a=Animal(name="Foo")
b=Animal(name='John')
b.children.append('Doe')

val = [
    asdict(x) for x in [a,b]
]

print(val)
mama
  • 2,046
  • 1
  • 7
  • 24