Class objects have a __bases__
(and a __base__
) attribute:
>>> class Foo(object):
... pass
...
>>> Foo.__bases__
(<class 'object'>,)
Sadly, these attributes aren't accessible in the class body, which would be very convenient for accessing parent class attributes without having to hard-code the name:
class Foo:
cls_attr = 3
class Bar(Foo):
cls_attr = __base__.cls_attr + 2
# throws NameError: name '__base__' is not defined
Is there a reason why __bases__
and __base__
can't be accessed in the class body?
(To be clear, I'm asking if this is a conscious design decision. I'm not asking about the implementation; I know that __bases__
is a descriptor in type
and that this descriptor can't be accessed until a class object has been created. I want to know why python doesn't create __bases__
as a local variable in the class body.)
All objects in Python have an attribute __dict__, which is a dictionary object containing all attributes defined for that object itself. The mapping of attributes with its values is done to generate a dictionary.
Attributes of a class can also be accessed using the following built-in methods and functions : getattr() – This function is used to access the attribute of object. hasattr() – This function is used to check if an attribute exist or not. setattr() – This function is used to set an attribute.
The self keyword is used to access the attributes and methods of the class. self just represents an instance of the class.
Python getattr() function is used to get the value of an object's attribute and if no attribute of that object is found, default value is returned. Basically, returning the default value is the main reason why you may need to use Python getattr() function.
I want to know why python doesn't create
__bases__
as a local variable in the class body
As you know, class
is mostly a shortcut for type.__new__()
- when the runtime hits a class
statements, it executes all statements at the top-level of the class
body, collects all resulting bindings in a dedicated namespace dict, calls type()
with the concrete metaclass, the class name, the base classes and the namespace dict, and binds the resulting class object to the class name in the enclosing scope (usually but not necessarily the module's top-level namespace).
The important point here is that it's the metaclass responsabilty to build the class object, and to allow for class object creation customisations, the metaclass must be free to do whatever it wants with its arguments. Most often a custom metaclass will mainly work on the attrs
dict, but it must also be able to mess with the bases
argument. Now since the metaclass is only invoked AFTER the class body statements have been executed, there's no way the runtime can reliably expose the bases
in the class body scope since those bases could be modified afterward by the metaclass.
There are also some more philosophical considerations here, notably wrt/ explicit vs implicit, and as shx2 mentions, Python designers try to avoid magic variables popping out of the blue. There are indeed a couple implementation variables (__module__
and, in py3, __qualname__
) that are "automagically" defined in the class body namespace, but those are just names, mostly intended as additional debugging / inspection informations for developers) and have absolutely no impact on the class object creation nor on its properties, behaviour and whatnots.
As always with Python, you have to consider the whole context (the execution model, the object model, how the different parts work together etc) to really understand the design choices. Whether you agree with the whole design and philosophy is another debate (and one that doesn't belong here), but you can be sure that yes, those choices are "conscious design decisions".
I am not answering as to why it was decided to be implemented the way it was, I'm answering why it wasn't implemented as a "local variable in the class body":
Simply because nothing in python is a local variable magically defined in the class body. Python doesn't like names magically appearing out of nowhere.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With