__bases__ misleading error message

Marco Buttu marco.buttu at gmail.com
Sun Jan 25 11:30:05 CET 2015

On 25/01/2015 01:55, Terry Reedy wrote:

> 'This situation' being that Someclass.attro works but Someclass().attro
> raises...
> In other words, if 'Someclass.attro' evaluates to an object ...
> then 'Someclass().attro' *normally* evaluates to the same object

I am sorry Terry, but I do not agree, because the word "normally" in 
this context does not have any meaning, and instroduces just confusion. 
In facts this is exactly the case where "Someclass.attro' evaluates to 
an object" *but* hasattr(Someclass(), 'attro'), as expected, is False. 
What do you mean with "normally"?

> because attribute lookup on an instance reverts to attribute lookup on
> the class and even its super classes

Here's the point. The __bases__ attribute is defined by the class type. 
So if isinstance(obj, type) is true, then hasattr(obj, '__bases__') is 
true. In the OP case:

   >>> class Sub: # Python 3
   ...     pass
   >>> isinstance(Sub, type)
   >>> hasattr(Sub, '__bases__')

But Sub() is not an instance of type (because Sub is not a subclass of 
type), and so Sub() does not have to get the attributes, like __bases__, 
from type, and here's we are:

   >>> foo = Sub()
   >>> isinstance(foo, type)
   >>> foo.__bases__
   Traceback (most recent call last):
   AttributeError: 'Sub' object has no attribute '__bases__'

In other words, speaking about the lookup machinery, because '__bases__' 
is not in foo.__dict__ Python looks for __bases__ in Sub.__dict__, but 
it does not found it. So it looks in the Sub bases, and we went back to 
the point: Sub is an instance of type, not a subclass of type.

> Someclass.__bases__
> is special; it is not listed by dir(Someclass), and it is not accessible
> via an instance.

In my point of view no attribute is special (maybe just a descriptor is 
a bit special, in some ways). To undestand what happens in these 
situations, we do not have to give a special meaning to the attribute. 
Given `obj.attr`, we just have to know what kind of object is `obj`: 
usually, like in this case, we have to differentiate between classes and 
non-classes objects. In fact __bases__ is not listed by dir(Sub) because 
Sub is a class, and the distinction between classes and non-classes 
objects matters, especially for dir()

Marco Buttu

More information about the Python-list mailing list