I think the question is that of style, which is to say, if you want a class method, should you call it as a class method MyClass.my_func()
, or as an instance method myinst.my_func()
. On of the of documented explinations of the @classmethod
decorator is that it will allow you to call the class method as if it was an instance method. I have included an example showing this below.
As for style, I think it should not be confusing to people either way, it really is the method implementation detail. If you are calling the class method in the context of an instance (i.e. as a user of a class instance object , or inside class instance methods), then calling class method as just another instance method is perfectly okay, and maybe even preferred to not highlighting some implementation detail about the method being called.
What would I do? If I was passing an instance attribute into a classmethod, I'd probably call the classmethod in the MyClass.my_func(self.some_value)
, rather then calling self.my_func(self.some_value)
because seeing the latter makes me wonder why my_func
isn't reading self.some_value
itself, instead of making me pass it along. Otherwise I really don't mind either form.
Of course, classes are meant to be instantiated, and the biggest faux pas is programmers using them as some sort of namespace for stateless methods.
class A:
value = 2
def __init__(self, value):
self.value = value
def add_instance(self, number):
self.value += number
@classmethod
def add_class(cls, number):
cls.value += number
def add_class_via_instance(self, number):
self.add_class(number)
def add_class_via_class(self, number):
A.add_class(number)
def add_class_via_sneak(self, number):
self.__class__.value += number
a = A(1)
print(f'{A.value=} {a.value=}')
a.add_instance(3)
print(f'{A.value=} {a.value=}')
A.add_class(3)
print(f'{A.value=} {a.value=}')
a.add_class_via_class(3)
print(f'{A.value=} {a.value=}')
a.add_class_via_instance(3)
print(f'{A.value=} {a.value=}')
a.add_class_via_sneak(3)
print(f'{A.value=} {a.value=}')
returns
A.value=2 a.value=1 # expect class and instance have different value values
A.value=2 a.value=4 # adding to the instance
A.value=5 a.value=4 # adding to the class
A.value=8 a.value=4 # calling the function as a class method works on the class attribute
A.value=11 a.value=4 # calling the function as a instance method works on the class attribute as well
A.value=14 a.value=4 # instance methods can access class values and therefore can behave as a classmethod if they want.