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_trickbefore setting a.trick result in a different outcome?
*Here's what I've read so far, are there better explanations?