Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Object-Oriented Python (retired) Inheritance Score Method

Y. Kravets
Y. Kravets
10,350 Points

Unfortunately another Python Object Oriented question

Hi (again) to everybody. As probably became obvious I am digging through an Object Oriented part of Python for the first time and its not going very well.

The code below doesn't work and despite watching lectures I seem to have a few important questions:

  1. usage of 'self': what does it actually denote/refer to (conceptually) and when do we use it? Why we don't use it in the arguments the method takes, like for example: python def(self, player)

but we do use it in the body of the method, like:

self.player
  1. When we call a method inside itself (recursively I believe) like for example: python def score(self): return self.score()

why do we use self in the return?

Well, as you can see there are some pretty fundamental questions exposing my lack of proper understanding of the topic so I would be really grateful if some makes it crystal clear for me because I'd really like to understand it well.

Thanks, Yevgen

game.py
class Game:
  def __init__(self):
    self.current_score = [0, 0]

  def score(self, player):
    self.player = input('> ')
    if self.player == 1:
      return self.current_score[0] + 1
    elif self.player == 2:
      return self.current_score[1] + 1
    else:
      return self.score()

Yevgen, When you build a class, let's use Game, it is really a holder of all the methods and attributes of that class object. You can then instantiate a Game object and it can do some 'stuff' for you. The only way you can work with any of the methods or attributes inside the object is through the 'self' reference. Inside your game you can have other variables without the 'self' but you will not be able to see them or manipulate them from the instantiated object. In a way, the self is giving you a handle to the methods and attributes of that object.

This probably doesn't answer all of your questions but I hope it is a start.

Ron

5 Answers

Kenneth Love
STAFF
Kenneth Love
Treehouse Guest Teacher

Hey!

OK, so, let's start with self. self is a reference back to the instance that you're working on. Uh, let's get an example.

class Pet:
    name = None

    def __init__(self, name):
        self.name = name

    def come_here(self):
        print("Come here, {}".format(self.name))


dog = Pet("Rover")
cat = Pet("Fluffy")

Pretty simple class. We have an __init__ method that'll be fired whenever the class is created. It's looking for a single argument to the class which we'll set as the name on our instance. How do we know it's set on the instance? Because we used self, which refers back to the instance. Let's see how that plays out.

>>> dog.come_here()
"Come here, Rover"
>>> cat.name
"Fluffy"

Why didn't we have to provide an argument for the self in come_here()? Well, let's look at one more example. Feel free to try this out, too.

>>> cat.come_here()
"Come here, Fluffy"
>>> Pet.come_here(cat)
"Come here, Fluffy"

Whoa, they both gave the same output. self, like I said, is an instance of the class. It's one Pet amongst thousands. Python likes us and wants us to be able to use a nice API for interacting with our code. So if we call a method (like come_here) on a instance, Python uses that instance as the first argument to the method. Or, we can call a method directly on a class and we give an argument to that method that's an instance of that class, but I think you'll agree that's a lot more work.

So, anytime we want to refer back to the instance that we're working with, we use self. And since all methods of a class (at least all of the ones we've been writing) work on instances, they all take self as the first argument, so the class knows what instance to use for the method.

Y. Kravets
Y. Kravets
10,350 Points

Thank you Ron & Kenneth! I appreciate the detailed response. I think I get the idea you are trying to bring across. Lets try and see if I can put it to proper use!

Y. Kravets
Y. Kravets
10,350 Points

However still, question remains:

Why does the code below does not work as expected:

class Game:
  def __init__(self):
    self.current_score = [0, 0]

  def score(self, player):
    self.player = input('> ')
    if self.player == '1':
      return [self.current_score[0] + 1, self.current_score[1]]
    elif self.player == '2':
      return [self.current_score[0], self.current_score[1]+1]
    else:
      return score()

P. S. Happy New Year to anyone reading this :)

EDIT:

Ok, so I have managed to make it happen as below. Please let me know if this is an efficient way? Can you also avoid using str for getting an output rather than a memory allocation?

class Game:
  def __init__(self):
    self.current_score = [0, 0]

  def score(self, player):
    if player == 1:
      self.current_score[0] += 1
    elif player == 2:
      self.current_score[1] += 1

  def __str__(self):
    return self.current_score
Kenneth Love
Kenneth Love
Treehouse Guest Teacher

You don't have to define __str__ to pass the challenge. I don't think anyone would check the string version of the instance instead of just getting the values directly from the instance.

And, yes, your solution is efficient enough.

Philip Ondrejack
Philip Ondrejack
4,287 Points

My intention isn't to hijack this thread but to use it to show differences. I've noticed that there is more than one way to solve most challenges. My question is what is considered pythonic? Would this code be considered pythonic? This is the code that I wrote to pass this same challenge:

class Game:
  def __init__(self):
    self.current_score = [0, 0]

  def score(self, player):

    if player == 1:
      self.current_score[0] += self.current_score[0] + 1

    if player == 2:
      self.current_score[1] += self.current_score[1] + 1
Kenneth Love
Kenneth Love
Treehouse Guest Teacher

So, self.current_score[0] += self.current_score[0] + 1 is the same as self.current_score[0] = self.current_score[0] + self.current_score[0] + 1, which means that if self.current_score[0] is 2, after this code, it would be 5.

I think you are using 'pythonic' style code however to be more concise you can change your incrementing to:

def score(self, player): self.current_score[player-1] += 1

This will cover both player one and player 2.