I'm trying to understand f their are differencies between self
and cls
but I'm struggle, even if it exists alot of topic about that. For instance:
class maclass():
A = "class method"
def __init__(self):
self.B = "instance method"
def getA_s(self):
print(self.A)
def getA_c(cls):
print(cls.A)
def getB_s(self):
print(self.B)
def getB_c(cls):
print(cls.B)
C = maclass()
C.getA_s()
C.getA_c()
C.getB_s()
C.getB_c()
which give me:
class method
class method
instance method
instance method
So whatever I use self
or cls
It aways refer to the same variable. When I add a self.A
in the Init__
, the cls.A is just replaced
def __init__(self):
self.B = "instance method"
self.A = "new instance method"
and I get:
new instance method
new instance method
instance method
instance method
I don't understand the point having two way to call class member if they are the same? I know this is a common question on this forum but yet I really don't understand why we can use different words to refer to the same thing (we even could use whatever the word instead of self
or cls
)
update
In the following case:
class maclass():
A = "class method, "
def __init__(self):
self.A = "instance method, "
def getA_s(self):
print(self.A) #give me "instance method, "
@classmethod
def getA_c(cls):
print(cls.A) #give me "class method, "
C = maclass()
C.getA_s()
C.getA_c()
print(' ')
print(C.A) #give me "instance method, "
I get :
instance method,
class method,
instance method,
So in this case, in maclass
cls.A
or self.A
do not refer to the same variable.
All your methods are instance methods. None of them are class methods.
The first argument to a method is named
self
only by convention. You can name it anything you want, and naming itcls
instead will not make it a reference to the class. That the first argument is bound to an instance is due to how method lookup works (accessingC.getA_s
produces a bound method object, and calling that object causesC
to be passed into the original functiongetA_s
), the names of the parameters play no role.In your methods, you are merely referencing instance attributes. That the
A
attribute is ultimately only defined on the class doesn't matter, you are still accessing that attribute throughC.A
(whereC
is the instance you created), notmaclass.A
. Looking up an attribute on the instance will also find attributes defined on the class if there is no instance attribute shadowing it.To make a method a class method, decorate it with the
@classmethod
decorator:Now
cls
will always be a reference to the class, never to the instance. I need to stress again that it doesn't actually matter to Python what name I picked for that first argument, butcls
is the convention here as that makes it easier to remind the reader that this method is bound to the class object.Note that if you do this for the
getB_c()
method, then trying to accesscls.B
in the method will fail because there is noB
attribute on themaclass
class object.That's because
classmethod
wraps the function in a descriptor object that overrides the normal function binding behaviour. It is the descriptor protocol that causes methods to be bound to instances when accessed as attributes on the instance, aclassmethod
object redirects that binding process.Here is a short demonstration with inline comments, I used the Python convertions for naming classes (using CamelCase), and for instances, attributes, functions and methods (using snake_case):
Note that the class method accesses the class attribute even though we set an attribute with the same name on the instance.
Next is binding behaviour:
The bound methods tell you what they are bound to, calling the method passes in that bound object as the first argument. That object can also be introspected by looking at the
__self__
attribute of a bound method: