TL;DR: You can use Descriptors to achieve this.
While the existing answers work for OP's case, they do not generally solve "How have access to both cls and self in a method".
E.g., here is the definition of two Python classes:
class MyClass:
def __init__(self, name):
self.name = name
# TODO: def foo
class MySubclass(MyClass):
pass
Where I would like to implement MyClass.foo
such that it exhibits the following behavior for any subclass MySubclass
of MyClass
:
MySubclass.foo() == MySubclass.__name__
MySubclass(name="bar").foo() == "bar"
If one could pass both cls
and self
in the method, this would be easy:
# Does not work because `self` is never set
@classmethod
def foo(cls, self=None):
if self:
return self.name
return cls.__name__
In these kind of cases, you can use Descriptors to build an object that mimics the behavior you want your method to have:
class MyDescriptor:
def __get__(self, instance, cls): # instance = self, cls = cls
if instance is None:
return lambda: cls.__name__
else:
return lambda: instance.name
class MyClass:
def __init__(self, name):
self.name = name
foo = MyDescriptor()