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

Matthew Rigdon
Matthew Rigdon
8,223 Points

Why do we use "self" for some functions and not on others?

What is the exact reason that we use "self" in some functions, and sometimes we don't. Here is an example.

class Combat:
    dodge_limit = 6
    attack_limit = 6

    def dodge(self):
      roll = random.randint(1, self.dodge_limit)
      return roll > 4

    def attack(self):
      roll = random.randint(1, self.attack_limit)
      return roll > 4

Notice how:

def dodge(self):
    roll = random.randint(1, self.dodge_limit)
    return roll > 4

Inherits self. Why don't you just write def dodge()? Also, inside of the code there is a regular variable, roll that isn't written as self.roll. When do you use self, and when do you not?

Thanks for the help!

1 Answer

Class method definitions all show an argument that refers to the calling instance of that method. The dodge()method uses the instance represented by the self object to determine which Combat object's dodge_limit to use as the maximum value for the roll.

You don't need to enter it inside the parentheses when you call it, though, because it's already specified. Say the game has two Combat objects battling right now, Matthew and Grendel. You either called Matthew.dodge() or Grendel.dodge(). There's no reason to have to type Grendel.dodge(Grendel).

The Python doc for Classes is helpful. Referring to the example class

Python
class MyClass:
    """A simple example class"""
    i = 12345
    def f(self):
        return 'hello world'

it says "The call x.f() is exactly equivalent to MyClass.f(x)."

As for roll vs. self.roll, it's mainly a matter of scope. roll is just a throwaway variable. Because of the way the game is structured, you don't want Grendel.roll to be available for other code; you just want to know if the roll was a success or a failure. If you would decide to implement some kind of tiebreaker later where you need to know the last value rolled, you could use self.roll instead, and it would work like attack_limit and dodge_limit. Calling Matthew.attack() would set Matthew.roll (but not return it), and Grendel.roll is a separate value. (If you did implement that, you would probably want to name them more clearly, like self.last_attack_roll and self.last_dodge_roll.)