-2

I am new in OOP and I am trying to understand why it wouldn't work if we wouldn't copy the sound.

class Pet():

    sounds = ['Mrrp']
    def __init__(self, name = "Kitty"):
        self.name = name
    # copy the class attribute, so that when we make changes to it, we won't affect the other Pets in the class
        self.sounds = self.sounds[:]

   def teach(self, word):
        self.sounds.append(word)
Yokanishaa
  • 75
  • 5

1 Answers1

3

You shouldn't define sounds as a class variable in the first place; having a class variable and an instance variable that share the same name is just begging for confusion. Just initialize it to its default in your __init__:

class Pet:
    def __init__(self, name = "Kitty"):
        self.name = name
        self.sounds = ['Mrrp']

The comment in your original code explains the purpose of that line pretty well; if you have a class variable sounds, and you set your instance variable to the same value as the class variable, anything you do to mutate that value is shared across the entire class. The slice operator [:] returns a copy of the list, instead of the original list, so that self.sounds and Pet.sounds are two different lists. (At the time you run the line self.sounds = self.sounds[:], the self.sounds on the right is actually the class variable Pet.sounds, but Pet.sounds is "shadowed" within self as soon as you assign a value to self.sounds.)

To avoid this type of confusion (and it is easy to get confused with code like this, even if you're experienced): if you want a value to be shared across a class, make it a class variable; if you want it to be unique to each instance, make it an instance variable. Don't make it one and then the other.

Samwise
  • 68,105
  • 3
  • 30
  • 44