Courses/Python Mastery/Module 9: Object-Oriented Python
Module 9 · Lesson 225 minBeginner

__init__, self, and Methods

Lesson goal
Construct objects properly and demystify self forever.

__init__, self, and Methods

Last lesson, you attached data to objects by hand — s1.name = "Aarav" — with nothing forcing consistency. Today, the __init__ constructor makes every object born complete, and self finally gets explained.

__init__ — the birth function

__init__ (double underscore each side — "dunder init") runs automatically when an object is created. It's the setup crew:

code
class Student:
    def __init__(self, name, marks):
        self.name = name
        self.marks = marks

# creating objects — arguments flow into __init__
s1 = Student("Aarav", 92)
s2 = Student("Diya", 95)

print(s1.name)     # Aarav
print(s2.name)     # Diya — each object has its OWN data

Trace the flow of Student("Aarav", 92):

  • Python creates a fresh, empty Student object
  • It calls __init__(self, "Aarav", 92) — self is the new object, "Aarav" and 92 are your arguments
  • Inside, self.name = name attaches "Aarav" to *that specific object*
  • The finished object is returned to s1
  • Now every Student is born with name and marks. No object can exist half-formed — the constructor enforces the shape.

    self — the object itself

    self is the most confusing word for beginners and the simplest idea once it lands: self is the object the method was called on.

    code
    class Student:
        def __init__(self, name, marks):
            self.name = name        # "attach name to THIS object"
    
        def introduce(self):
            print(f"I'm {self.name}, scored {self.marks}")
    
    s1 = Student("Aarav", 92)
    s2 = Student("Diya", 95)
    
    s1.introduce()     # I'm Aarav, scored 92
    s2.introduce()     # I'm Diya, scored 95

    The trick: s1.introduce() secretly means introduce(s1) — Python passes the object as self automatically. Inside the method, self.name means "the name of *whichever object I was called on*." That's why s1 prints Aarav and s2 prints Diya with the same method.

    The two self-rules:

  • self is always the first parameter of every method
  • You never pass it yourself — Python does, via the dot
  • Methods using their own data

    Methods become powerful when they compute from the object's attributes:

    code
    class Student:
        def __init__(self, name, marks):
            self.name = name
            self.marks = marks
    
        def average(self):
            return sum(self.marks) / len(self.marks)
    
        def has_passed(self):
            return self.average() >= 40      # methods calling methods!
    
    s1 = Student("Aarav", [85, 90, 78])
    print(s1.average())        # 84.33...
    print(s1.has_passed())     # True

    self.marks inside average() refers to the calling object's list. And has_passed calls self.average() — objects' methods work together through self.

    The full anatomy, one screen

    code
    class Student:
        def __init__(self, name, marks):     # constructor: birth setup
            self.name = name                 # attributes: the data
            self.marks = marks
    
        def introduce(self):                 # method: behavior
            print(f"I'm {self.name}")
    
        def average(self):                   # method computing from data
            return sum(self.marks) / len(self.marks)
    
    
    s1 = Student("Aarav", [85, 90, 78])      # instantiation
    s1.introduce()                           # method call

    Read it as a sentence: *"A Student is born with a name and marks; it can introduce itself and compute its average."*

    Common Errors & Fixes

  • `TypeError: Student() takes no arguments` — you defined __init__ with a typo (_init_, __init_). Dunders need double underscores on both sides.
  • `NameError: name 'self' is not defined` — you forgot self as the method's first parameter.
  • `TypeError: introduce() takes 0 positional arguments but 1 was given` — defined without self but called via the dot (which passes the object). Add self.
  • Attribute "disappears" — you set it on one object, read it from another. Each object's attributes are its own.

  • ✅ Checkpoint

  • When does __init__ run? *(Automatically, at object creation)*
  • What is self? *(The object the method was called on — passed automatically)*
  • Why does s1.introduce() print Aarav and s2.introduce() print Diya? *(self refers to the calling object each time)*
  • Can a method call another method? *(Yes — through self)*
  • Next: inheritance — building new classes on top of existing ones.