When I run the code below, I get a reference to the parent class A
at the end, while I was hoping to refer to the child B
.
In [1]: class A:
...: def f():
...: print(__class__)
...:
In [2]: class B(A): pass
In [3]: B.f()
<class '__main__.A'>
I know I can do something like
In [4]: class A:
...: def f(self):
...: print(self.__class__)
...:
In [5]: class B(A): pass
In [6]: B().f()
<class '__main__.B'>
but I'm wondering if there is any way I could drop the extra parentheses.
CodePudding user response:
If you want to be able to call the function on the class as well, not just an instance, and know which class it was called on (and for an instance, the class of the instance it was called on), make the method a classmethod
, e.g.:
class A:
@classmethod
def f(cls):
print(cls)
class B(A):
pass
The classmethod
decorator makes a descriptor that will automatically provide the class object it was called on, whether it was called on the class itself or an instance of the class, and provides the class object as the first argument, rather than an instance. It's almost exclusively used to define alternate constructors (for the purpose of taking some argument format not accepted by __init__
, converting from that format to one __init__
accepts, then ending with return cls(converted args here)
), but if you're really insistent on:
- Using classes for this, and
- Not making instances of the classes for whatever reason
it can handle both your use cases (B.f()
and B().f()
); classmethod
strips instance information when called, so the latter behaves identically to the former (they both pass B
as the value of cls
in f
).
print(__class__)
alone didn't work because __class__
is intentionally tied to the class the function was defined in, as part of the machinery for making no-arg super()
calls work (it uses some pretty awful hacks to make super()
behave like it was really called with the first positional argument passed to the function, typically self
, plus a __class__
variable smuggled into a closure scope when the class the function was defined in finishes being defined); making __class__
redefine itself based on being called on a subclass would turn all uses of super()
into infinite recursion.