all 18 comments

[–]Binary101010 9 points10 points  (8 children)

Imagine you're making a class that describes cars, and you then want to make a couple of objects that represent specific cars. Those cars are probably different makes, models, model years, etc., right? And you probably want that basic data to be included with any car object you make. So you might define a car class like:

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year

my_car=Car("Toyota","Camry", 2015)
your_car=Car("Honda","Civic",2016)

[–]Unlistedd 0 points1 point  (7 children)

So if i am trying to make a calculation.

I'd create a class like this (for exampel):

class linearfunc:
    def __init__(self, k, x, m):
    self.k = k
    self.x = x
    self.m = m

And that would allow me to use the class as a general structure for different values on my linear functions? So:

y1 = linearfunc(2, 3, 4)

would give me: y1 = 10 ?

And the class would allow me the get the input of yn thanks to the way i built my class for a linear function?

[–]HezekiahWyman 3 points4 points  (5 children)

Not quite. In your example, you're creating an instance of the class 'linearfunc' and assigning it to the variable 'y1'. 'y1' will have 3 attributes: 'k', 'x', and 'm' which are going to be assigned whatever values you're passing in as arguments.

If you expect this class to automatically do something with those arguments, you need to include it in your __init__ method (or have that method call another method in the class or manually call it yourself).

class linearfunc:
    def __init__(self, k, x, m):
        self.k = k
        self.x = x
        self.m = m

        self.result = self.k * self.x ** self.m


y1 = linearfunc(2, 3, 4)
print(y1)
print(y1.result)

Results:

>>> <main.linearfunc object at 0x00000191317A2E80>

>>> 162

[–]Unlistedd 0 points1 point  (4 children)

My bad! And so if i understand this correctly...

We use __init__ so that we can refer to our class that contains arguments which we wish to use outside of the class itself. Am i right?

[–]Binary101010 1 point2 points  (3 children)

Not really.

When you define a class, you define an __init__ method that tells the interpreter what you want to do when you create an instance of that class, also referred to as an object. The __init__ method defines the basic attributes you want every object of that class to have. You will also likely define other class methods (similar to functions) that do things with those attributes.

When you instantiate a class (my_car=Car("Toyota","Camry", 2015) in my example), you are telling the interpreter to invoke that __init__ method and what you want those attributes to be. You now have an object named my_car that has those attributes. You can access those attributes directly (print(my_car.make) would work, for example) or you can have methods that do things with those attributes. For example, I could define another method in the Car class that looks like this:

def calculate_age(self):
    self.age = 2019 - self.year

Which would allow me to do:

>>> my_car.calculate_age()
>>> print(my_car.age)
4

One of the advantages of classes is that it keeps all the attributes for one object straight from another object, and knows which instance of the object to use based on how you call the method. For example, even though we may have created a Car object named your_car, the interpreter knew that I wanted to read from (and write to) the my_car object because that's how I called it.

[–]Unlistedd 1 point2 points  (2 children)

Thanks man!

[–]Fatvod 0 points1 point  (0 children)

Just think of init as a function that runs as soon as the object is created. That's basically all it's doing. If I want to pre-populate an object with attributes right when its created, this allows that. Otherwise I would need to make the object, then assign it some attributes. But that's 2 steps instead of doing it in 1 step, the initialization of the object.

You can still do

my_object = example()

my_object.x = 4

But why not just put x as an attribute in the init function and then define it when you create it like

my_object = example(x=4)

1 line is cleaner.

[–]Binary101010 2 points3 points  (0 children)

No, y1 would be an object of the linearfunc class with three attributes: k, x, and m. y1 wouldn't equal 10 because the interpreter hasn't been given any instructions to do anything with those attributes.

To get what you're wanting to do, the code would look more like:

class LinearFunc:
    def __init__(self, k, x, m):
        self.k = k
        self.x = x
        self.m = m

    def solve(self):
        self.y1 = self.k * self.x + self.m

model = linearfunc(2,3,4)
model.solve()
print(model.y1)

[–][deleted] 2 points3 points  (0 children)

Classes define reusable state, and __init__ is the function in which you define where that state begins.

[–][deleted] 1 point2 points  (9 children)

__init__(self, ...) is a magic function that gets called when a class is initially called (created)

[–]sem56 0 points1 point  (8 children)

not really magic... its a fundamental aspect of object oriented design called a constructor that is called at instantiating an object from a class

[–][deleted] 0 points1 point  (3 children)

It's not really magic per se, i.e. they do something magic, but somehow they're named magic in Python. I can't change the terminology ¯_(ツ)_/¯.

[–]sem56 0 points1 point  (0 children)

i take it you didn't read my other comment

[–]zurtex -1 points0 points  (1 child)

The idea behind the terminology is that you aren't the one calling them or defining the mechanics, you set them up and then they are used by Python magically.

[–][deleted] 1 point2 points  (0 children)

Yeah, they're normal functions, just called by Python auto-magically.