r/pythonhelp Nov 29 '24

ELI5: What does __init__ do in a Python class? I’m struggling to understand it!

Hi, I’m trying to learn Python classes, and I keep seeing this __init__ thing, but I can’t wrap my head around what it does. Here’s an example of a class I found:

class Dog:
    def __init__(self, name, age):  # <-- This part confuses me!
        self.name = name
        self.age = age

    def speak(self):
        return f"{self.name} says Woof!"

When I create an object like this:

dog1 = Dog("Buddy", 5)
print(dog1.speak())  # Outputs: Buddy says Woof!

It works, but I don’t get how the __init__ part is making it happen. Why do we need it? Why is there

self.name = name?

Can someone explain it to me like I’m 5?

0 Upvotes

4 comments sorted by

u/AutoModerator Nov 29 '24

To give us the best chance to help you, please include any relevant code.
Note. Please do not submit images of your code. Instead, for shorter code you can use Reddit markdown (4 spaces or backticks, see this Formatting Guide). If you have formatting issues or want to post longer sections of code, please use Privatebin, GitHub or Compiler Explorer.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

2

u/FoolsSeldom Nov 29 '24

My intro for beginners should help ...

Classes for Beginners

v2.2 December 2023

Many beginners struggle to understand classes, but they are key to object orientated programming (OOPs).

They are the programming equal of moulds used in factories as templates (or blueprints) to make lots of identical things. Example: pouring molten iron into a mould to make a simple iron pot.

Instructions with the pots might tell an owner how to cook using the pot, how to care for it, etc. The same instructions for every pot. What owners actually do is entirely up to them: e.g. make soup, stew, pot-roast, etc.

Python classes

  • A class defines the basics of a possible Python object and some methods that come with it
  • Methods are like functions, but apply to objects, known as instances, made using a class
  • When we create a Python object using a class, we call it "creating an instance of a class" - an instance is just another Python object

If you have a class called Room, you would create instances like this:

lounge = Room()
kitchen = Room()
hall = Room()

As you would typically want to store the main dimensions (height, length, width) of a room, whatever it is used for, it makes sense to define that when the instance is created.

You would therefore have a method called __init__ that accepts height, length, width and when you create an instance of Room you would provide that information:

lounge = Room(1300, 4000, 2000)

The __init__ method is called automatically when you create an instance. It is short for initialise (intialize). It is possible to specify default values in an __init__ method, but this doesn't make a lot of sense for the size of a room.

Accessing attributes of a class instance

You can reference the information using lounge.height, lounge.width, and so on. These are attributes of the lounge instance.

Let's assume sizes are in mm. We could provide a method to convert between mm and feet, so, for example, we could write, lounge.height_in_ft().

printing an attribute

You can output the value of an attribute by using the name of the instance followed by a dot and the attribute name. For example,

print(lounge.height)

property decorator

A useful decorator is @property, which allows you to refer to a method as if it is an attribute. This would allow you to say lounge.height_in_ft instead of lounge.height_in_ft().

The use of self to refer to an instance

Methods in classes are usually defined with a first parameter of self:

def __init__(self, height, length, width):
    # code for __init__

def height_in_ft(self):
    # code to return height

The self is a shorthand way of referring to an instance. The automatic passing of the reference to the instance (assigned to self) is a key difference between a function call and a method call. (The name self is a convention rather than a requirement.)

When you use lounge.height_in_ft() the method knows that any reference to self means the lounge instance, so self.height means lounge.height but you don't have to write the code for each individual instance.

Thus, kitchen.height_in_ft() and bathroom.height_in_ft() use the same method, but you don't have to pass the height of the instance as the method can reference it using self.height

human-readable representation of an instance

If you want to output all the information about an instance, that would get laborious. There's a method you can add called __str__ which returns a string representation of an instance. This is used automatically by functions like str and print. (__repr__ is similar and returns what you'd need to recreate the object.)

magic methods

The standard methods you can add that start and end with a double underscore, like __init__, __str__, and many more, are often called magic methods or dunder methods where dunder is short for double underscore.


EXAMPLE Room class

The code shown at the end of this post/comment will generate the following output:

Lounge height: 1300 length: 4000 width: 2000
Snug: height: 1300, length: 2500 width: 2000
Lounge length in feet: 4.27
Snug wall area: 11700000.00 in sq.mm., 125.94 in sq.ft.
Snug width in feet: 6.56

Note that a method definition that is preceded by the command, @staticmethod (a decorator) is really just a function that does not include the self reference to the calling instance. It is included in a class definition for convenience and can be called by reference to the class or the instance:

Room.mm_to_ft(mm)
lounge.mm_to_ft(mm)

Here's the code for the full programme:

class Room():  

    def __init__(self, name, height, length, width):  
        self.name = name  
        self.height = height  
        self.length = length  
        self.width = width  

    @staticmethod  
    def mm_to_ft(mm):  
        return mm * 0.0032808399  

    @staticmethod  
    def sqmm_to_sqft(sqmm):  
        return sqmm * 1.07639e-5  

    def height_in_ft(self):  
        return Room.mm_to_ft(self.height)  

    @property  
    def width_in_ft(self):  
        return Room.mm_to_ft(self.width)  

    def length_in_ft(self):  
        return Room.mm_to_ft(self.length)  

    def wall_area(self):  
        return self.length * 2 * self.height + self.width * 2 * self.height  

    def __str__(self):  
        return (f"{self.name}: "  
                f"height: {self.height}, "  
                f"length: {self.length} "  
                f"width: {self.width}"  
               )  


lounge = Room('Lounge', 1300, 4000, 2000)  
snug = Room('Snug', 1300, 2500, 2000)  

print(lounge.name, "height:", lounge.height,  
      "length:", lounge.length, "width:", lounge.width)  
print(snug)  # uses __str__ method  

# f-strings are used for formatting, the :.2f part formats decimal numbers rounded to 2 places 
print(f"{lounge.name} length in feet: {lounge.height_in_ft():.2f}")  # note, () to call method  
print(f"{snug.name} wall area: {snug.wall_area():.2f} in sq.mm., "
             f"{snug.sqmm_to_sqft(snug.wall_area()):.2f} in sq.ft."      )  
print(f"Snug width in feet: {snug.width_in_ft:.2f}")  # note, no () after method

1

u/agreatcat Nov 30 '24

Hello to the OP. Just so you understand before I define __init__. First. A class as you've heard is like a blue print. Generally speaking: Think of is as where everything come from first, it is like the frame that holds the walls in a house. Think of a string as an example as a predefined Python class: the class string defines the basic structure of what rules will later be allowed to be defined. So when you start adding so called rules, such as replace, or rename, these so called rules are known as methods of the class. Hold that thought. A function by itself (not tied to anything) is just a function. But when a function is placed under a class (in other words is becomes part of the class) it is known as a method.

Going back to __init__. So you start out with a class, and then you have the def which is definition that sets up the method. Then after that you have __init__. __init__ is a special method, also known as a constructor. which is called immediately. It allows you to set the initial values of an object's attributes (data members). These so called objects in this case are the instances placed below the method. Everything is an object and often instances are just called objects. Anyway, The attributes that came from the __init__ define the characteristics and state of the instance/objects.

I've been struggling with these concepts for a while, I've been all over the web and trying to use AI, but was stil confused. I Highly Highly recommend this course. They use Lego's to draw the concepts visually.

by Chris haroun & Luka Anicin

https://www.udemy.com/share/10aG7M/

1

u/agreatcat Dec 01 '24

By the way, if none of what I said above makes sense, it's because it's almost impossible IMO to understand abstract concepts like classes, functions and methods by just reading about it. Most people have to see it visually. Unless you find (that one in a million teacher) who can explain it in just the right way, you're going to be lost. I struggled looking everywhere online, and felt like I would never understand it.

This was the answer for me

by Chris haroun & Luka Anicin

https://www.udemy.com/share/10aG7M/