Understanding classes, init and self

Thanks, your and other explanation helped a lot.

1 Like

Might also be good to point out – and perhaps this helps understanding better – that self is just an arbitrary name, you can also define a class as follows:

class Student:
    def __init__(this, name, age):
        this._name = name
        this._age = age

  def get_age(this):  
        # since this is an instance method 
        # the first argument always refers back to a Student
        # (an instance of the Student class)
        # it doesn't matter how that argument is named
        return this._age

   @staticmethod
   def has_age():
        return True

>>> x = Student("Jan", 101)
>>> x.get_age()
101
>>> Student.has_age()
True

Update: Sorry, I missed the fact that @DerSchinken had already pointed this out in a note :slight_smile:

So if I am using tk.Toplevel.__init__(self), I guess I do not need to set mastercalass as the parameter of the currentclass. So the code excerpt would look like this?

class NewWindow(): 
  def __init__(self):
    tk.Toplevel.__init__()
    self.title("Another window")

Does it mean, that while the self on the second line creates the instance of NewWindow class, the self in the fourth line points to title() method of tk.Toplevel masterclass? And the only way how the interpreter knows where the self is located is because Toplevel masterclass was initialized before - line 3?

You guessed wrong :blush:. Calling __init__ does not create an inheritance relationship. That is created by telling what you want to inherit from.

class NewWindow(): 

does not mean that it inherits from nothing, it is just a shorthand for

class NewWindow(object): 

If you want to inherit from Toplevel, you write:

class NewWindow(tk.Toplevel): 

Your statement/expression

tk.Toplevel.__init__()

will fail, because the attribute self (defined on __init__) is missing. As said before, there is nothing special about self, the name is just a convention, it needs to be defined or passed in into your method/function.

OK.

Yup, that is my typographic error.

Just to emphasize a key point here, you aren’t “loading” the class into memory (the class is already in memory); rather, you are creating a new instance of the class, which gets automatically passed to the self variable of methods called on that instance. Implementation-wise, a class and its instance aren’t that different in Python (compared to other language), but what’s really important is the conceptual difference.

Extending my previous example, you wouldn’t expect to tell a blueprint of a motorcycle to accelerate and have it actually drive off, right? :slight_smile: You’d need to create one or more actual motorcycles (instance of Motorcycle) and call .accelerate() on that.

Funny enough, my post above that started out as focusing on the fact that self is just an arbitrary name chosen by convention, but after I shifted gears to focus more on the class vs instance aspect, it ended up being just a footnote :slight_smile:

Just to point out here that your original code:

class NewWindow(tk.Toplevel): 
  def __init__(self):
    super().__init__()
    self.title("Another window")

is perfectly fine and the conventional, idiomatic way for doing this; using tk.Toplevel.__init__(self) is useful in the sense that it helps you understand what Python is doing behind the scenes, but in practice you’d want a good reason to deviate from the standard, expected super().__init__() approach.

1 Like