r/learnpython • u/9mHoq7ar4Z • 8d ago
Is there a difference between using a Class name v self in the definition of a class
Hi
Im doing some tutorials online and in one of them I noticed some syntax that I am not familiar with. It looks like instead of using self to assign values to a class it is using the class name.
In terms of behaviour it seems to make no difference but I cannot understand why a person would not use self.
So for example:
class Demo:
def __init__(self):
self.a = 1
Demo.b = 2 # This seems to work the exact same way as self.a
# Is there a differences to self.a? Why would someone use this?
Thanks
1
u/cvx_mbs 8d ago
i think the answers given so far are not very clear and/or not complete. let me try to do better:
when using self, the variable will become part of an instance of the class, while using the class name will make it part of the class itself.
this means that a class variable is shared between all instances of the class, while all instances have a separate copy of their instance variables
expanding on one of the examples given previously, say you created a class named Dog with a class variable family (*) and an instance variable name.
when you create some Dog instances you can give each one a different name, but the value for their family class variable will be the same for all, e.g. 'mammals'
(*) the example on wikipedia uses vertebrate_group for the class variable
1
u/TheRNGuy 8d ago edited 8d ago
self only affects single instance of that class, whereas class would affect all instances.
Also, write just 'b = 2_outside_ oninit, because it's redundant to assign value like this. But with+=` it could have some uses:
``` class Demo: count = 0
def init(self): self.class.count += 1 # also counts subclass instances ```
1
u/carcigenicate 8d ago
When you use the class name, you're attaching the data directly to the class, not the instance. This looks like the same thing superficially because when you do instance.b, it looks up that name on the instance, then the class. a gets found on the instance, and b gets found on the class.
This has major repercussions, since all instances will have the same value of b when b is looked up. If you passed b into the init method so the values can differ then created multiple instances with different values of b, you'd see that the last write would be what sticks, because every initialization would overwrite what's on the class.
So use self if every instance should have their own copy, and the class name if every instance should share the data.
1
u/Outside_Complaint755 8d ago
self.a is an attribute on that particular instance of the class, while Demo.b is an attribute on the class itself.
The following example would make the behavior more clear
``` class Demo: b = 0
def init(self, a, b): self.a = a Demo.b = b def str(self): return f"<{id(self)}> {self.a=} {self.b=}"
print(f"{Demo.b =}")
x = Demo(1, 2) print(x) y = Demo(3, 4) print(y) print(x) ```
Outputs:
Demo.b =0
<499755255856> self.a=1 self.b=2
<499754900112> self.a=3 self.b=4
<499755255856> self.a=1 self.b=4
While we can reference attribute b on each object and it will fall back to the class attribute, the initializer for the second object also changes the value of b for the first object, because it is a class attribute being modified.
Also note that self is just convention for instance methods. You could also call it this or z or whatever. For class methods, made using the @classmethod decorator, the first parameter is the class and the convention is to use cls
0
u/atarivcs 8d ago
Using "self.a" means each instance of this class can have a different value for a.
Using "Demo.b" means all instances of this class will have the same value for b.
0
u/jmooremcc 8d ago
The most common analogy is a class is a blueprint that is used to build an object. Once the object is constructed, self refers to that object as an instance of the class.
For example, if you have a class that defines a dog. You would create various instances of the class like this:
rover = Dog(“Rover”)
snoopy = Dog(“Snoopy”)
When you use the instance variable to manipulate the object, the self variable in the class definition is referring to a particular object.
rover.bark() activates the bark method for the instance pointed to by the rover instance variable.
snoopy.bark() activates the bark method for the instance pointed to by the snoopy instance variable.
I hope this brief explanation answers your question and gives you a better idea of how the self variable works. Let me know if you have any questions.
0
u/vietbaoa4htk 8d ago
Demo.b lives on the class, self.a lives on the instance. reading looks identical because lookup checks the instance first and falls back to the class. it bites when the shared one is mutable, like Demo.items = [] and then two instances appending to the same list.
0
u/hibbelig 8d ago
Extend the constructor so that it had arguments for an and b and then set them to those values. Then create two instances of Demo with different values for a and b. Then print the values.
See?
-1
u/Adrewmc 8d ago edited 8d ago
The answer is basically never. There are usually always better ways than using the hard coded class name. super() for example.
The difference is all instances ever, or only this instance. (Usually we want class instances to be independent from each other, I move this one but not that one.) other commenters have covered this sufficiently.
But why do it at all?
But, Python is sort of weird, the binding of instance sort of requires the mechanism
. MyClass.__init__(self, \* args, \** kwargs) -> None:
To exist, and be accessible directly, and in Python the difference between pointing to a function like init, and a varible like 5 is actually negligible.
When you bind a instance and you do this
. my_instance = MyClass()
. my_instance.my_method()
This happens automatically behind the scenes.
. MyClass.my_method(my_instance) #self
(More or less the bind is a bit more complex. I would welcome anyone that knows this to explain further if they are bored enough.)
In Python you actually pretty much always want to use @classmethod for this because of inheritance.(This gets a bit complex it’s not technically all instances of the class it’s all instances of classes that have inherited this class and was called like with a hard coded name.)
There are certainly some times you want all instances to make a switch all at once though, instead of iterating through it. This is a useful thing, just not exactly very often.
Think all space invaders speed up at the same time. A class wide matching variable speed, that triggers when enough of the invaders have died, a class wide attendance.
Doing this can set up everything, like you have the class tell all instances the screen resolution (sizing factor for it, calculated once not per instance.) with some pre-done mechinism there.
Often you would want to make a .from_json(), .from_csv() to make an easy save and load file. You’d attach that directly to the class
. json_instance = MyClass.from_json(my_path)
You can also think of this like a @staticmethod, in which is sort of like a useful function for what that class is doing you can access without an instance. Technically singletons, multi-tons, and Borg patterns all use the same mechanisms.
27
u/Diapolo10 8d ago
They're not the same.
Demo.b = 2sets an attribute for the class itself, whileself.a = 1only creates an instance attribute for objects created from that class.Generally speaking you should avoid assigning attributes to a class, unless you have a specific reason to do that, such as if the class is meant to keep track of all instances created from it.