Implicit accessing of __class__

Hi there

Recently, I saw someone wrote code like this:

class A:
    def __init__(self):
        print(__class__) # -> A
        print(self.__class__) # -> A
A()

I didn’t know that it worked!
Why can __class__ attribute be accessed without an instance, exceptionally? Why cannot other attributes such as __mro__, __dict__, __module__, etc.?
I tried to search on google but I couldn’t find any information…

cf. Link: Built-in Types — Python 3.11.0 documentation

1 Like

There’s a subtle difference between __class__ and self.__class__: the former is the class that this function is defined in, and is necessary for the zero-argument form of super(). In Python 2, this feature didn’t exist, and the only way to call super was to do something like super(A, self) - in Python 3, the no-arg form super() is equivalent to super(__class__, self) where self really is “the first positional argument to this function”.

So if you want to know about the actual type of the object you’re working with, self.__class__ (or type(self) which does a similar job) will do that, but to refer to the class that this method was defined in - rare other than for calling super() - use __class__ on its own.

2 Likes

Try this:

class B(A):
    pass

B()

Does that help or make things more confusing? :slight_smile:

See an in-depth discussion with many links to the history of this feature here.

1 Like

Thank you very much for your reply.
I was wondering how and why super().* works, and your answer cleared two questions for me!

Yeah, :exploding_head: :sleeping_bed::sunglasses:!
Thank you for the link. I’ve never imagined it is related to super magic.