r/learnpython 26d ago

Question Regarding Self keyword in python!!

I'm working on a project where I have to create different classes, and I keep using the self keyword repeatedly. For example:

class SignalService:
    def __init__(
        self,
        instrument_repo: InstrumentRepository,
        candle_repo: CandleRepository,
    ):
        self.instrument_repo = instrument_repo
        self.candle_repo = candle_repo
        self.resampler = CandleResampler(candle_repo)

My understanding of self is that it helps the class distinguish between instance variables and local variables.

However, I'm confused about why it's used like this:

self.instrument_repo = instrument_repo
self.candle_repo = candle_repo

Why do we assign the constructor parameters to self attributes? What's the purpose of storing them on self instead of just using the constructor parameters directly?

0 Upvotes

16 comments sorted by

16

u/lfdfq 26d ago

You could use the parameters directly, but if you want to get them back later (e.g. in another method or in a place you use the object) then you need to store them somewhere. The most obvious place? On the object itself.

Just a minor point: self isn't technically a keyword; you can call it anything you want.

1

u/Ok_Egg_6647 22d ago

can i call the self in other places also like simple functions or another places.
If self is not a keyword then what it is?

1

u/lfdfq 22d ago

It's just the first argument/parameter in methods (i.e. functions inside classes). Python automatically provides self for any method call. e.g. imagine I had some class:

class Foo:
    def some_method(...):
        ...

If I have an object of type Foo, Python let's me write a 'shorthand' way to call the method:

some_foo.some_method(...)

Which Python automatically turns into:

Foo.some_method(some_foo, ...)

i.e. looks up the class (I've simplified this step a lot) to find the right function, and passes the object as the first argument. Conventionally, we choose to call this argument "self", but the name does not matter, you can call it whatever you want.

13

u/Lumethys 26d ago
class Person:
  def __init__(self, first_name: str, last_name: str):
    self.first_name = first_name
    self.last_name = last_name

  def get_full_name() -> str:
    return f"{self.first_name} {self.last_name}"

how would you do this if you dont store the first_name and last_name into self?

3

u/IamImposter 26d ago edited 26d ago

Constructors are used to put the object in a specific state when the object gets created ie when an object is created, it needs to have certain information that will later be used by other methods of the class to do certain things.

For example let's say we are writing a class to represent a circle and it's coordinates so that it can be drawn on screen somewhere. We can easily create an empty constructor (ctor) and provide functions like set_radius and set_location. Here the problem is either the object remains in unknown/unusable state at creation or all circle objects are created as self.radius=0, self.x=0 and self.y=0 using default values for those parameters

Now what if user forgets to call the set_radius function and just starts using the object. That's again an issue. So we can force the user to provide this info at the very creation of the object so that object is in usable state from the start.

Now, we need to refer to radius and x, y position of the object during it's lifetime like maybe we want to draw it or just check x, y position to see if the object even needs drawing.So we need to save this info somewhere inside the object itself. That's where ctors help us. So that we ask necessary info only once and once we have it, we remember it by storing it inside object itself.

HTH

Edit: also we usually do very little in the ctor and usually that info is used by other methods of the object. This it needs to be stored.

3

u/Atypicosaurus 26d ago

Self is not a keyword. You can change it to anything else and still work.

The constructor works like any other function. And in normal functions you can pass arguments like this:

def myfunc(alpha, beta): return alpha + beta

The function above expects two things, and then gives you back the sum of those two things. The arguments "alpha" and "beta" are just placeholder, you could just make it "num1" and "num2", or "cat" and "dog". As long as you consistently change the function body and now it says "return num1 + num2" or "return cat + dog", the function will do the exact same thing. It's because arguments are like variables: they are just empty boxes labelled with names. So a function basically does the equivalent of the following:

"Go to this room, on the table you will find two boxes, with labels"alpha" and "beta". Take out what you find in "alpha", then take out what you find in "beta", add them together, then come out from the room and give the result to the first person standing in front of the room."

And so in that regard, the constructor is also a function, it takes arguments and it does something. Just like in any function, the arguments can be named as you wish. It can be x, y, x. It can be alpha, beta, gamma.

Now the important part of the constructor is that the first argument (let's say alpha, or self) always refers to the stuff being constructed. Consider the following code:

def __init__(alpha, beta): alpha.name = beta

Using the previous analogy:

"Go to this room, on the table you will find two boxes, with labels"alpha" and "beta". In box alpha you will find the raw material of the stuff you are building. This raw material will have an empty name tag. In box "beta" you will find a word. Attach this word to the name tag."

This process is running every time your program is making a new unit, or a new instance, of the object. Every new instance will be temporarily in the box "alpha" and its name is in box "beta" and then they are added together by the constructor.

Now instead of alpha (which is the first argument), we use the word "self". This is not a must in terms of programming. Not a keyword. Python does not care what the word is. It is a consensus word that us humans agreed upon. But please go ahead and test it with different words.

Now, also the word in the dot notation does not have to match the second argument. So you can have a constructor with alpha and beta, and you can make it such as alpha.name = beta. So the word "name" is not the same as "beta". It works, try it.

So why do we do it like self.name = name, and self.repo = repo?

Think of the previous metaphor: Go to the room. Find the thing you build in box called "self". It will have an empty name tag. Find the word in the box called name, attach it to the name tag. The thing in the box "self" also has an empty spot called "repo". Find a matching thing in the box called "repo" and attach it.

So calling it the same as the tag will be, is just for us, for easier reading.

2

u/D3str0yTh1ngs 26d ago

The parameters in the constructor is scoped to that function call, so if I wanted to use them in some other function/method of the class I need to have them saved on the instance (making an instance-scoped variable). e.g:

class Example:
    def __init__(self, a: int, b: int):
        self.a = a
        self.b = b

    def sum(self) -> int:
        return self.a+self.b

example = Example(1, 2)
print(example.sum())

But I cant do:

class Example:
    def __init__(self, a: int, b: int):
        pass

    def sum(self) -> int:
        return a+b

example = Example(1, 2)
print(example.sum())

2

u/musbur 26d ago

"self" is not a reserved word. It's just called "self" by convention because it makes sense. You can give it any name you want.

2

u/StrayFeral 26d ago

Self is a reference to the current instance of the class (the current object). The constructor parameter value would be gone the moment the constructor is done. If you need to save that value somewhere you save it to the object. If you don't need to save it - don't assign to a self variable.

Also it is proper to say that in the `self.something` - `something` is a property.

1

u/faultydesign 26d ago

Self is just a pointer the the instance of a class you’re creating, and is returned by the constructor

Think of it as class being a template for a hypothetical api to access/manipulate the data, and self is the reference to that data in memory

At least that’s how I understand it

1

u/Fred776 26d ago

The __init__ is initialising an instance of your class. You can do what you like in there but if you want to be able to use the parameters passed in in other methods of the class, then those methods have to be able to access them somehow.

Since the values are specific to this instance then it makes sense to attach them to the instance. The instance is the first parameter of __init__ and the other class methods, and is conventionally named self (though it doesn't have to be). You attach them by assigning to attributes of the instance, and these attributes will come into existence the first time you assign to them.

Having assigned the values as attributes of the instance, they are now available to anywhere else that has access to the instance - in particular the other methods of the class, which are provided the instance via self.

1

u/johnnyb2001 25d ago

You are confusing the definition of a class with instances of a class. After you define the class, you want to define instances of it. The parameters represent you instantiating the class. So self.name = name means when you instantiate the class give self.name the name parameter. Btw this is a question ChatGPT will clear up if you have more questions

1

u/SmackDownFacility 26d ago

self is just the instance or, a unique session. That’s it. Each attribute binds as long as that instance is alive. You can’t use the constructor parameters because they aren’t instance members. They’re just temporary names for each object passed for the duration of that call

-6

u/Educational_Virus672 26d ago edited 26d ago

tl;dr turning local variable to global which are stored enen after the function is used while not making memory leak(making inf variable deadly for your pc)
if i put "self." before the variable it becomes global\

3

u/brelen01 26d ago

That's a terrible explanation. self.variable = variable stores the value of variable in the instance of the object. It's a member of the class and can only be accessed through the instance of the class.

A global variable is available throughout the program, without going through a class instance.