0

I am trying to understand something in Python.

When I have a property that I want shared across all subclasses, I place it in the parent class. I was expecting that the actual value of this property would be unique for each object instance. However, if this property is iterable and I modify it in one object, the change is made for all other instantiated objects.

class Animal:
    sounds = []
    def add_sounds(self, sound):
        return self.sounds.append(sound)

class Cat(Animal):
    pass

class Dog(Animal):
    pass    

cat = Cat()
cat.add_sounds('meow')

dog = Dog()
dog.add_sounds('bark')

print('The cat says: ' + str(cat.sounds))
print('The dog says: ' + str(dog.sounds))

This gives:

The cat says: ['meow', 'bark']
The dog says: ['meow', 'bark']

... but I was expecting:

The cat says: ['meow']
The dog says: ['bark']

This doesn't seem to be the case for other variable types like strings or numbers. What am I missing? This is Python 3.7.3.

1 Answers1

2

sounds is a class attribute shared by all instances. You want an instance attribute instead, which is best initialized in Animal.__init__.

class Animal:
    def __init__(self):
        self.sounds = []

    def add_sounds(self, sound):
        self.sounds.append(sound)

In your code, since sounds doesn't exist as an attribute on an individual instance of Animal, self.sounds resolves to Animal.sounds.

The difference you are observing with strings and numbers is the those types are immutable; you don't specify how you observe the difference, but here's an example:

x = 3
y = x
x += 1
assert y == 3

The += operator doesn't modify the existing int that both x and y refer to; it creates a new int object and makes x refer to that, leaving y as the sole reference to the previous int object.

chepner
  • 497,756
  • 71
  • 530
  • 681