4

I understand __class__ can be used to get the class of an object, it also can be used to get current class in a class definition. My question is, in a python class definition, is it safe just use __class__, rather than self.__class__?

#!/usr/bin/python3

class foo:
    def show_class():
        print(__class__)

    def show_class_self(self):
        print(self.__class__)


if __name__ == '__main__':
    x = foo()
    x.show_class_self()
    foo.show_class()
./foo.py
<class '__main__.foo'>
<class '__main__.foo'>

As the codes above demonstrated, at least in Python3, __class__ can be used to get the current class, in the method show_class, without the present of "self". Is it safe? Will it cause problems in some special situations? (I can think none of it right now).

2
  • 1
    I'm surprised it resolves the bare reference to __class__. Commented Oct 27, 2022 at 4:43
  • Actually, I'm surprised too! That is the reason I ask whether it is a common idiom. Commented Oct 27, 2022 at 4:47

2 Answers 2

1

That is documented in the datamodel, so I believe it is safe/reliable.

From 3.3.3.5. Executing the class body:

Class variables must be accessed through the first parameter of instance or class methods, or through the implicit lexically scoped __class__ reference described in the next section.

From 3.3.3.6. Creating the class object:

__class__ is an implicit closure reference created by the compiler if any methods in a class body refer to either __class__ or super

It is true that the docs mention any methods, your foo.show_class is a function but perhaps not convincingly a method. However PEP 3135, which added this reference, is worded differently:

Every function will have a cell named __class__ that contains the class object that the function is defined in. ... For functions defined outside a class body, __class__ is not defined, and will result in runtime SystemError.

Sign up to request clarification or add additional context in comments.

Comments

0

__class__ is lexically scoped, whereas some_object.__class__ is dynamically dispatched. So the two can different when the lexical scope is different from the of the receiver, like if lambdas are involved:

#!/usr/bin/env python3

class ClassA:
    def print_callback(self, callback):
        print(callback(self))
        
class ClassB:
    def test(self):
        ClassA().print_callback(lambda o: o.__class__) # <class '__main__.ClassA'>
        ClassA().print_callback(lambda _: __class__) # <class '__main__.ClassB'>
        
ClassB().test()

It depends on what you're trying to achieve. Do you want to know which class's source code region you find yourself in, or the class of a particular object?

And I think it goes without saying, but I'll mention it explicitly: don't rely on the attribute directly, use the type function. I.e. prefer type(o) over o.__class__.

11 Comments

It's not so confusing if you understand why __class__ is there in the first place (to allow zero-argument super() to work).
This is a great video on how super() works, for anyone interested in what @wim is referencing
Interesting thing I found: __class__ produces an LOAD_DEREF opcode, not a LOAD_GLOBAL (e.g. used for __main__) or LOAD_ATTR/LOAD_METHOD (used for any other attributes/methods)
Not sure why that's interesting? It's documented as a closure reference and LOAD_DEREF is the usual opcode for loading closure vars..
I also don't think it's quite right to say to prefer type(o) over o.__class__ because in some cases these can refer to different things.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.