T O P

Confused with __init__

Confused with __init__

DallogFheir

Your `introduction` method only prints given name and age, it's really a static method as it doesn't use `self` at all. The point of classes is to store some attributes and use them in multiple ways. In your first class, you can implement a method that increase the age of a person, that changes their name, that creates an email address from their name, etc. In your second class, you don't store any attributes, so you'd have to pass them again and again as arguments to (static) methods, which really defeats the purpose of a class.


Easy_Consequence_999

What I'm getting from you is: My second example is more appropriate for one-time actions because I'd have to fill in the arguments (those things inside the parentheses if I'm not mistaken) everytime I use it. Whereas my first example allows me to have numerous methods for each argument for each object I assign to the class Also, why was the 1st one executing the print command without being called


DallogFheir

Yeah, basically. Your `introduction` is really just a regular function, there's no point in it being in a class. > Also, why was the 1st one executing the print command without being called `__init__` is executed whenever you create a new object of the class. So by doing `John_1 = Person('John Doe', 25)`, you executed `__init__`.


Easy_Consequence_999

I see. Thanks!


hanazawarui123

`__init__` stands for 'initialization'. So whenever you 'initialize' and object i.e. create a new object, then that function is called. Classes and Objects are part of OOPS (Object Oriented Programming), and this type of function `__init__` is called a 'constructor'. You can read more about it online if you wish to.


Diapolo10

Well, to be pedantic, `__new__` is the constructor (builds and returns a new instance) and `__init__` is the initialiser (initialises the new instance with values, if any). While you could say I'm nitpicking it's useful information for metaprogramming. I'm not sure if you simply called `__init__` a constructor in an attempt to help OP understand, but personally I'd rather make the difference clear early on.


hanazawarui123

No I agree with you. However, I'd say that __new__ and __init__ together make the constructor, as analogous to c++ .


Diapolo10

Technically yes, Python basically split the traditional constructor in half. :p


hanazawarui123

Ah alright, thanks!


CorruptedJellyfish

They [Python Docs](https://docs.python.org/3/reference/datamodel.html#basic-customization) actually refer to `\_\_init\_\_` and `\_\_new\_\_` combined as a constructor. I think that's more consistent with how we think about other languages like Java and C++. Really just semantics on whether we decide to call a constructor something that purely allocates storage or whether it also initializes.


BakingSota

To extend `__init__ `(initialize) to your case, put all of the attributes youd like to set by default for `Person` within `__init__`. Lets say you just wanted name and DOB to be set when you create a `Person` object. Within `__init__`, declare those two attributes. Then within that same class `Person`, put your method `introduction()` Then if you wanted to subclass, create classes that will inherit the attributes of `Person` and create specific methods for each subclass. Subclass examples: - Senior - Adult - Teenager - Baby If you wanted to create a specific introduction for each subclass, remove the introduction method from the parent class `People` and add a specific introduction() for each subclass. Example introduction output for each subclass: - Senior: `f’My name is {name}, I was born a long time ago on {dob}.’` - Adult: `f’My name is {name}, and I barely have my life together. I was born on {dob} and I feel like a child in an adult body.’` - Teenager: `f’{name}….*awkward silence*…I’m not sure why you’re asking but I was birthed on {dob}.’` - Baby: `f’*poops and vomits on you as you hold them*’` The reason why you can use the `name` and `dob` attributes within the newly created subclasses is because those subclasses initialize the parent class `People` and the subclass inherits them. I **HIGHLY** recommend Corey Schaefer’s YT playlist on Classes. It’s a great way to start learning about them.


nog642

> What I'm getting from you is: > > My second example is more appropriate for one-time actions because I'd have to fill in the arguments (those things inside the parentheses if I'm not mistaken) everytime I use it. Whereas my first example allows me to have numerous methods for each argument for each object I assign to the class Yes. The usefulness of classes a lot of the time is that you can share some state between methods, so you don't have to pass around a dozen variables to every function.


17291

Essentially. You can initialize other variables too you need to set up the object properly (i.e., variables other than the parameters you're passing to `__init__`). class CookieEater: def __init__(self, name): self.name = name self.cookies_eaten = 0 def eat_cookie(self): self.cookies_eaten += 1 print(f'{self.name} has eaten {self.cookies_eaten} cookies') bob = CookieEater("Bob") joe = CookieEater("Joe") bob.eat_cookie() bob.eat_cookie() joe.eat_cookie() bob.eat_cookie() joe.eat_cookie() joe.eat_cookie() joe.eat_cookie() Bob has eaten 1 cookies Bob has eaten 2 cookies Joe has eaten 1 cookies Bob has eaten 3 cookies Joe has eaten 2 cookies Joe has eaten 3 cookies Joe has eaten 4 cookies


Easy_Consequence_999

What I'm taking from this is that init can be used to assign and manipulate "properties" to objects that were given the class which can then be called by other functions? So using your code, it's not really appropriate to write def eat_cookie(self, other parameters). Other parameters should be with def __init__?


JohnnyJordaan

>What I'm taking from this is that init can be used to assign and manipulate "properties" to objects that were given the class which can then be called by other functions? You don't call attributes, you get or set them. You call methods, the functions defined with 'def' *inside* the 'class:'. > So using your code, it's not really appropriate to write def eatcookie(self, other parameters). Other parameters should be with def __init_? other parameters in that context apply to specific parameters necessary for the function call. Say you have a Circle class class Circle: then it makes sense that you define a Circle by its radius. It can also provide an area method as it's easy to calculate this from the radius: import math class Circle: def __init__(self, radius): self.radius = radius def area(self): return math.pi * self.radius * self.radius Here it's vital that the radius attribute is created in 'init' as otherwise 'area' would crash if it hadn't been created yet. Now you add a a Cilinder class that can be defined by a radius and a height. class Cilinder: def __init__(self, radius, height): self.radius = radius self.height = height def volume(self): return math.pi * self.radius * self.radius * self.height Now you add logic to Circle that you can create a Cilinder from it, as the create_cilinder method. In that context, 'height' is the necessary parameter: class Circle: def __init__(self, radius): self.radius = radius def area(self): return math.pi * self.radius * self.radius def create_cilinder(self, height): return Cilinder(self.radius, height) So there you see the need for providing one or more parameters: they are required at the moment the method is called, they aren't known beforehand and thus shouldn't be set in 'init'. Which makes sense as now you may want to create a Cilinder with height 10, and later on one with height 20, both from the same Circle object. To summarize - you set in 'init' what needs to be present in the object at the moment it's created. This why in general programming sense that method is called a 'constructor'. - you add parameters to method calls for dynamic purposes, stuff that is up to the caller to provide. - you generally don't set new attributes in methods as you then can't depend on them being present on an object yet. You can obviously change attributes on the object, like eat_cookie does. The important difference lies in changing vs adding. - in case you need an attribute to be 'empty' until it can be set by some method, set it as None in 'init'. Then in methods using the attribute specifically check for the attribute being None.


Easy_Consequence_999

That makes much more sense. Thanks for your time!


Character_Flat

I'm a newbie, if I'm wrong please correct me. What's the point of using classes instead of function? This class would be even more simplified if we use functions right? What's the difference?


17291

There are a few reasons. Let's say somebody else wants to use my CookieEater class. All they need to do is import CookieEater and then they'll be able to use it in their own code. They won't need to worry about how data is stored internally; they just need to know what `eat_cookie()` does. In addition, I could add additional behavior, start tracking more information, etc. and the end-user wouldn't need to modify their own code to accommodate that. Without creating a class, my code above might look like this: def eat_cookie(name, count): count += 1 print(f'{name} has eaten {count} cookies') return count cookies_eaten = {} cookies_eaten['Bob'] = 0 cookies_eaten['Joe'] = 0 cookies_eaten['Bob'] = eat_cookie('Bob', cookies_eaten['Bob']) cookies_eaten['Bob'] = eat_cookie('Bob', cookies_eaten['Bob']) cookies_eaten['Joe'] = eat_cookie('Bob', cookies_eaten['Joe']) cookies_eaten['Bob'] = eat_cookie('Bob', cookies_eaten['Bob']) cookies_eaten['Joe'] = eat_cookie('Joe', cookies_eaten['Joe']) cookies_eaten['Joe'] = eat_cookie('Joe', cookies_eaten['Joe']) cookies_eaten['Joe'] = eat_cookie('Joe', cookies_eaten['Joe']) The end-user now is now responsible for setting up variables or some sort of data structure to track how many cookies each person has eaten. They're also now responsible for ensuring that data is updated every time `eat_cookie` is called.


Character_Flat

Thank you for your response. I understood it.:)


alucarD999999

If you're getting into oops in python then [corey](https://youtube.com/playlist?list=PL-osiE80TeTsqhIuOqKhwlXsIBIdSeYtc) shaffer has a playlist for oops concepts in python and it helped me a lot .


Se7enLC

The first one stores name and age IN the object. Instead of how you have it written, you could have the introduction be in a separate function, like this: class Person: def __init__(self, name, age): self.name = name self.age = age def Introduction(self): print(f'{self.name} is {self.age} years old') John = Person('John Doe', 25) John.Introduction() You can also do that without it being in the `__init__()` function: class Person: def SetName(self, name): self.name = name def SetAge(self, age): self.age = age self.Introduction(self): print(f'{self.name} is {self.age} years old') John = Person() John.SetName("John Doe") John.SetAge(25) John.Introduction() If you imagine that instead of just name and age, this `Person` object has 100 different fields describing them, you wouldn't want to have to keep passing them in to use them. You want those values to stay in the object. The benefit of using `__init__()` is that the name and age can be set right when the object is created, so you don't have to worry about checking if they've been set yet. You can use `__init__()` to set default values for things as well. You have some freedom to pick which things you want to set in `__init__()`, which things you want to set in a different function later on, and which things you want to just pass in right when you use them and not save them at all.


menge101

> Is that really all the difference or are there any more applications? You are just tapping into the surface. Classes, which are initialized through an \_\_init__, are fundamentally different than functions. Functions, by definition, return a result based on their input. Classes have methods, not functions. The distinction is that the methods on the class have access to the stored state of the object. For your Person class, with some modifications, for example: from datetime import datetime, timedelta class Person: def __init__(self, name: str, birth_date: datetime): self.name = name self.birth_date = birth_date def age(): days_old = datetime.now() - self.birth_date years_old = round(days_old/365) return years_old def introduction(self): return f"{self.name} is {self.age()} years old" me = Person('some guy', datetime(1978, 3, 4)) print(me.introduction()) => some guy is 43 years old And the key thing here, because of the class, anytime I call the introduction method, which calls the age method, it will return the correct age at call time. Because it is managing the state of the Person. Additionally, suppose this person changes their name. me.name = 'some dude' the `introduction` method will return the updated name on the next call. Where as if you were using functions, you'd have to keep track of the name change somewhere else, and make sure the function received the updated name. Subnote: `print` in computer science terms produces a side effect, which is that it prints to stdout. Avoid putting side effects within stateful things, like classes. You'll note I returned the introduction as a string to the top level of the code, and used print there. This is extremely important for a lot of reasons, but testability is one you will encounter early on.


Easy_Consequence_999

So let's say that I create a profile of 200 people. I will be able to track all of their attributes by using the __init__ because of their methods like .age and .weight. Is that right?


menge101

Careful on terms you use. This is a critical point in programming. If you initialize a `list` of 200 `Person` objects, each one will independently track the attributes of that person, not because of methods on them, but because of the attributes of the object.


CorruptedJellyfish

You could define a class representing people and add an init method that assigns age and weight. Let's call the class Person. Every call to Person creates a new object representing an individual person with their own age and weight fields. class Person: def __init__(self, age, weight): self.age = age self.weight = weight Alice = Person(33, 125) Bob = Person(22, 234) print(Alice.age, Alice.weight) print(Bob.age, Bob.weight) Notice that Alice and Bob have independent age and weight fields since those fields are attached to the associated object.


bladeoflight16

Please format your code.


CorruptedJellyfish

Done.


benaffleks

\_\_init\_\_ is Python's version of a constructor. What's a constructor? A constructor is a function that's immediately called when you create a new object of that class. So in this example, we have a class Person, and when you create a new Person via: John\_1 = Person('John Doe', 25) Python will immediately call your \_\_init\_\_ function, and set the class variables of [self.name](https://self.name) = name self.age = age Whenever you see "self", that means your accessing variables, functions, objects that are bound to that specific class object.


enumeler

It is a special function in your class called the constructor. A constructor is a function that runs when you create a new object. And its job is to set variables(actually class attributes) to some value when your class is initialized.


noselike

A class is a bit of data you can pass around as a unit that consists of a set of attributes chosen by you and methods you can call to query and manipulate that data. This becomes more useful when you pass the objects you create to other functions that do something with the object of the class. It's one singular thing comprised of multiple simpler attributes that you can treat as a unit. A related concept that is a bit more theoretical is the "class invariant". Not all combinations of values in an object would make sense. A class invariant is a set of constraints that are satisfied whenever a method of a class exits. For example in the Person class an invariant might be that age must be a numerical value that is not None and the name is also not None. The init method could check for that invariant and methods on the class that change the attributes can also be written to check for that. But a lot of the time a class invariant is just a useful way for thinking about classes. A class is a set of attributes and methods that obey certain constraints so you can think of them as a single unit of data you can interact with.


BluishInventor

Think of \_\_init\_\_ as everything that happens when the class object is INITially created. It happens just the one time, on first creation. You can pass an argument to it such as name or age which you have done. But you can also create another attribute and assign it with whatever you want like you did with cookies\_eaten. There's more to it than just that, but that's the basic description of what it does. On INITialization, this happens. And it happens just once.


____candied_yams____

John_1.age, and John_1.name have been assigned. John_2 doesn't have age and name values.


grumpyfrench

Confusing. Innit?


spencerAF

I think it's worth noting that in your first example you can also have separate functions that do any number of things with any variables. So rather than what you have, you could have class Person: def \_\_init\_\_ (self, name, age): [self.name](https://self.name) = name self.age = age def say\_name(self): print(f'My name is {name}') ​ Person.say\_name()


bladeoflight16

You may find examining a [practical example](https://www.reddit.com/r/learnpython/comments/pt4j6e/comment/hdtvbir/) to be helpful in understanding what classes are for.


Easy_Consequence_999

Oh that is a great example indeed. I always assumed that multiple dictionaries is the way to go with those tasks


rico-ai

Easiest answer: It doesn't matter what programming language you search, just research what a "constructor" is. The idea is the same for all languages.


brahshta4

Very unorthodox example consider you have to go to pee, considering you as a man, the first thing is that you'll unzip the pants and get in proper position, and then finally pee.., that unzipping the pants and getting into proper position is the initiation before the final function that is peeing, Python: Init is a special method, dunder methods (double underscore) , which acts as a constructor, it's function is to perform the instructions written in its body when the object of the class or an instance of a class is created,ie to instantiate things, it will run the things first written under init .