Consider the following difference between classic classes and the new style classes.
class A():
data = 'abcd'
def __getattr__(self, name):
return getattr(self.data, name)
class B(object):
data = 'abcd'
def __getattr__(self, name):
return getattr(self.data, name)
print(A()[0]) # Prints 'a'
print(B()[0]) # TypeError: 'B' object does not support indexing
I do know that explanation for this property is that new style objects attribute search starts at class instead of instances for builtin operations. But the class object too has __getattr__ defined and why it doesn't get invoked for the missing attribute here which is __getitem__.
I figured out the answer is that the __getattr__ is called only if the attribute search starts at the instance object. But if the attribute search explicitly on the class and instance is skipped __getattr__ is never called.
Hence in classic classes the search for __getitem__ starts at instance object and __getattr__ is invoked whereas in the new style class the search starts at class object and hence __getattr__ is not invoked.