I'm a novice Python programmer utterly confused by OOP and the need for self
in classes. I've read the many SO posts, blogs* etc that attempt to demystify it, but could use some help on this particular scenario.
I am basing the below scenarios off the Python2 tutorial on Class and Instance Variables. I'll lead with my examples, followed by explicit questions beneath.
First, I'll directly set tricks
, and then use the add_trick
method:
class Dog:
tricks = []
def __init__(self, name):
self.name = name
def add_trick(self, trick):
self.tricks.append(trick)
def print_self_tricks(self):
print(self.tricks)
a = Dog('spencer')
b = Dog('rex')
a.tricks = ['foo'] # How is this even possible? Where did I define self.tricks?
a.print_self_tricks()
['foo'] # Ok, the below results make sense
b.print_self_tricks()
[]
a.tricks
['foo']
b.tricks
[]
a.add_trick('jump')
a.print_self_tricks()
['foo', 'jump']
b.print_self_tricks()
[] # Great, as expected
a.tricks
['foo', 'jump']
b.tricks
[] # Great, as expected
Now, the exact same setup, but executed in a different order: add_trick
before direct setting of trick
.
class Dog:
tricks = []
def __init__(self, name):
self.name = name
def add_trick(self, trick):
self.tricks.append(trick)
def print_self_tricks(self):
print(self.tricks)
a = Dog('spencer')
b = Dog('rex')
a.add_trick('jump')
a.print_self_tricks()
['jump']
b.print_self_tricks()
['jump'] # Welp, that's not expected.
a.tricks
['jump']
b.tricks
['jump'] # Welp, that's not expected.
a.tricks = ['foo']
a.print_self_tricks()
['foo']
b.print_self_tricks()
['jump'] # Great, but inconsistent with the behavior above resulting from a.add_trick
a.tricks
['foo']
b.tricks
['jump'] # Great, but inconsistent with the behavior above resulting from a.add_trick
- Why does self.tricks exist? It was never defined in
__init__
(e.g. self.tricks = tricks). I wouldn't expect it to be possible to set self.tricks since it wasn't previously defined. - Why does my approach not result in a different answer? That is, why does
a.tricks = ['foo']
seem to behave as intended compareda.add_trick('roll over')
? - It seems like order of operations matters. Why does calling
add_trick
before setting a.trick result in a different outcome?
*Here's what I've read so far, are there better explanations?