I'm aware that under the hood C is accessing the type/object slots and that the workflow is different (here here). The well-written Python docs that mention the object.__getattribute__
workflow leave a lot of ambiguity about how to visualize it in Python. This ambiguity is probably legitimate because we can only talk about the workflow in terms of the C API. But isn't there a way to illustrate the call precedence using __dict__
attributes on the class and instance?
I'm aware that under the hood C is accessing the type/object slots and that the workflow is different (here). The well-written Python docs that mention the object.__getattribute__
workflow leave a lot of ambiguity about how to visualize it in Python. This ambiguity is probably legitimate because we can only talk about the workflow in terms of the C API. But isn't there a way to illustrate the call precedence using __dict__
attributes on the class and instance?
I'm aware that under the hood C is accessing the type/object slots and that the workflow is different (here). The well-written Python docs that mention the object.__getattribute__
workflow leave a lot of ambiguity about how to visualize it in Python. This ambiguity is probably legitimate because we can only talk about the workflow in terms of the C API. But isn't there a way to illustrate the call precedence using __dict__
attributes on the class and instance?
givenGiven this mixins.py
file:
class Boom(object):
def log(self):
print "[ BOOMTOWN ]: %s" % (self.__repr__())
class Basic(object):
def log(self):
print self.__class__
class Uno(Basic):
pass
class Dos(Basic):
pass
class Boom(object):
def log(self):
print "[ BOOMTOWN ]: %s" % (self.__repr__())
class Basic(object):
def log(self):
print self.__class__
class Uno(Basic):
pass
class Dos(Basic):
pass
simulateSimulate object.__getattribute__
:
from mixins import *
def object_getattribute(instance, klass, attrname, klass_mro=[]):
'''
NOTE: the resolution workflow
for Class.attrname lookups is different
'''
print "[ INSPECTING ]: %s" % klass
if attrname in klass.__dict__.keys():
print "yep, in Class.__dict__"
if ( hasattr( klass.__dict__[attrname], '__get__' )
and hasattr( klass.__dict__[attrname], '__set__' ) ):
print "yep, DATA descriptor found"
return klass.__dict__[attrname].__get__( instance, klass )
else:
print "nope, not a DATA descriptor"
else:
print "nope, not in Class.__dict__"
if attrname in instance.__dict__.keys():
print "yep, instance.__dict__"
return instance.__dict__[attrname]
else:
print "nope, not in instance.__dict__"
if attrname in klass.__dict__.keys():
print "yep, in Class.__dict__"
if hasattr( klass.__dict__[attrname], '__get__' ):
print "yep, NON-DATA descriptor found"
return klass.__dict__[attrname].__get__( instance, klass )
else:
print "return from Class.__dict__[ attrname ]"
return klass.__dict__[attrname]
else:
print "nope, not in Class.__dict__"
if hasattr( klass, '__getattr__' ):
print "return from Class.__getattr__( attrname )"
return klass.__getattr__( attrname )
else:
print "nope, no __getattr__ override"
return object_getattribute( instance,
klass_mro.pop(0), attrname, klass_mro=klass_mro )
from mixins import *
def object_getattribute(instance, klass, attrname, klass_mro=[]):
'''
NOTE: the resolution workflow
for Class.attrname lookups is different
'''
print "[ INSPECTING ]: %s" % klass
if attrname in klass.__dict__.keys():
print "yep, in Class.__dict__"
if ( hasattr( klass.__dict__[attrname], '__get__' )
and hasattr( klass.__dict__[attrname], '__set__' ) ):
print "yep, DATA descriptor found"
return klass.__dict__[attrname].__get__( instance, klass )
else:
print "nope, not a DATA descriptor"
else:
print "nope, not in Class.__dict__"
if attrname in instance.__dict__.keys():
print "yep, instance.__dict__"
return instance.__dict__[attrname]
else:
print "nope, not in instance.__dict__"
if attrname in klass.__dict__.keys():
print "yep, in Class.__dict__"
if hasattr( klass.__dict__[attrname], '__get__' ):
print "yep, NON-DATA descriptor found"
return klass.__dict__[attrname].__get__( instance, klass )
else:
print "return from Class.__dict__[ attrname ]"
return klass.__dict__[attrname]
else:
print "nope, not in Class.__dict__"
if hasattr( klass, '__getattr__' ):
print "return from Class.__getattr__( attrname )"
return klass.__getattr__( attrname )
else:
print "nope, no __getattr__ override"
return object_getattribute( instance,
klass_mro.pop(0), attrname, klass_mro=klass_mro )
class Foo(Uno,Dos): pass
func = object_getattribute( Foo(), Foo, 'log', klass_mro=Foo.mro()[1:] )
func()
print "\n"
class Foo(Boom,Uno,Dos): pass
func = object_getattribute( Foo(), Foo, 'log', klass_mro=Foo.mro()[1:] )
func()
print "\n"
class Foo(Uno,Boom,Dos): pass
func = object_getattribute( Foo(), Foo, 'log', klass_mro=Foo.mro()[1:] )
func()
print "\n"
class Foo(Uno,Dos,Boom): pass
func = object_getattribute( Foo(), Foo, 'log', klass_mro=Foo.mro()[1:] )
func()
print "\n"
class Foo(Uno,Dos): pass
func = object_getattribute( Foo(), Foo, 'log', klass_mro=Foo.mro()[1:] )
func()
print "\n"
class Foo(Boom,Uno,Dos): pass
func = object_getattribute( Foo(), Foo, 'log', klass_mro=Foo.mro()[1:] )
func()
print "\n"
class Foo(Uno,Boom,Dos): pass
func = object_getattribute( Foo(), Foo, 'log', klass_mro=Foo.mro()[1:] )
func()
print "\n"
class Foo(Uno,Dos,Boom): pass
func = object_getattribute( Foo(), Foo, 'log', klass_mro=Foo.mro()[1:] )
func()
print "\n"
[ INSPECTING ]: <class '__main__.Foo'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Uno'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Dos'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Basic'>
yep, in Class.__dict__
nope, not a DATA descriptor
nope, not in instance.__dict__
yep, in Class.__dict__
yep, NON-DATA descriptor found
<class '__main__.Foo'>
[ INSPECTING ]: <class '__main__.Foo'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Boom'>
yep, in Class.__dict__
nope, not a DATA descriptor
nope, not in instance.__dict__
yep, in Class.__dict__
yep, NON-DATA descriptor found
[ BOOMTOWN ]: <__main__.Foo object at 0x102b0f050>
[ INSPECTING ]: <class '__main__.Foo'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Uno'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Boom'>
yep, in Class.__dict__
nope, not a DATA descriptor
nope, not in instance.__dict__
yep, in Class.__dict__
yep, NON-DATA descriptor found
[ BOOMTOWN ]: <__main__.Foo object at 0x102b06fd0>
[ INSPECTING ]: <class '__main__.Foo'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Uno'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Dos'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Basic'>
yep, in Class.__dict__
nope, not a DATA descriptor
nope, not in instance.__dict__
yep, in Class.__dict__
yep, NON-DATA descriptor found
<class '__main__.Foo'>
[ INSPECTING ]: <class '__main__.Foo'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Uno'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Dos'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Basic'>
yep, in Class.__dict__
nope, not a DATA descriptor
nope, not in instance.__dict__
yep, in Class.__dict__
yep, NON-DATA descriptor found
<class '__main__.Foo'>
[ INSPECTING ]: <class '__main__.Foo'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Boom'>
yep, in Class.__dict__
nope, not a DATA descriptor
nope, not in instance.__dict__
yep, in Class.__dict__
yep, NON-DATA descriptor found
[ BOOMTOWN ]: <__main__.Foo object at 0x102b0f050>
[ INSPECTING ]: <class '__main__.Foo'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Uno'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Boom'>
yep, in Class.__dict__
nope, not a DATA descriptor
nope, not in instance.__dict__
yep, in Class.__dict__
yep, NON-DATA descriptor found
[ BOOMTOWN ]: <__main__.Foo object at 0x102b06fd0>
[ INSPECTING ]: <class '__main__.Foo'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Uno'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Dos'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Basic'>
yep, in Class.__dict__
nope, not a DATA descriptor
nope, not in instance.__dict__
yep, in Class.__dict__
yep, NON-DATA descriptor found
<class '__main__.Foo'>
given this mixins.py
file:
class Boom(object):
def log(self):
print "[ BOOMTOWN ]: %s" % (self.__repr__())
class Basic(object):
def log(self):
print self.__class__
class Uno(Basic):
pass
class Dos(Basic):
pass
simulate object.__getattribute__
:
from mixins import *
def object_getattribute(instance, klass, attrname, klass_mro=[]):
'''
NOTE: the resolution workflow
for Class.attrname lookups is different
'''
print "[ INSPECTING ]: %s" % klass
if attrname in klass.__dict__.keys():
print "yep, in Class.__dict__"
if ( hasattr( klass.__dict__[attrname], '__get__' )
and hasattr( klass.__dict__[attrname], '__set__' ) ):
print "yep, DATA descriptor found"
return klass.__dict__[attrname].__get__( instance, klass )
else:
print "nope, not a DATA descriptor"
else:
print "nope, not in Class.__dict__"
if attrname in instance.__dict__.keys():
print "yep, instance.__dict__"
return instance.__dict__[attrname]
else:
print "nope, not in instance.__dict__"
if attrname in klass.__dict__.keys():
print "yep, in Class.__dict__"
if hasattr( klass.__dict__[attrname], '__get__' ):
print "yep, NON-DATA descriptor found"
return klass.__dict__[attrname].__get__( instance, klass )
else:
print "return from Class.__dict__[ attrname ]"
return klass.__dict__[attrname]
else:
print "nope, not in Class.__dict__"
if hasattr( klass, '__getattr__' ):
print "return from Class.__getattr__( attrname )"
return klass.__getattr__( attrname )
else:
print "nope, no __getattr__ override"
return object_getattribute( instance,
klass_mro.pop(0), attrname, klass_mro=klass_mro )
class Foo(Uno,Dos): pass
func = object_getattribute( Foo(), Foo, 'log', klass_mro=Foo.mro()[1:] )
func()
print "\n"
class Foo(Boom,Uno,Dos): pass
func = object_getattribute( Foo(), Foo, 'log', klass_mro=Foo.mro()[1:] )
func()
print "\n"
class Foo(Uno,Boom,Dos): pass
func = object_getattribute( Foo(), Foo, 'log', klass_mro=Foo.mro()[1:] )
func()
print "\n"
class Foo(Uno,Dos,Boom): pass
func = object_getattribute( Foo(), Foo, 'log', klass_mro=Foo.mro()[1:] )
func()
print "\n"
[ INSPECTING ]: <class '__main__.Foo'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Uno'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Dos'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Basic'>
yep, in Class.__dict__
nope, not a DATA descriptor
nope, not in instance.__dict__
yep, in Class.__dict__
yep, NON-DATA descriptor found
<class '__main__.Foo'>
[ INSPECTING ]: <class '__main__.Foo'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Boom'>
yep, in Class.__dict__
nope, not a DATA descriptor
nope, not in instance.__dict__
yep, in Class.__dict__
yep, NON-DATA descriptor found
[ BOOMTOWN ]: <__main__.Foo object at 0x102b0f050>
[ INSPECTING ]: <class '__main__.Foo'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Uno'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Boom'>
yep, in Class.__dict__
nope, not a DATA descriptor
nope, not in instance.__dict__
yep, in Class.__dict__
yep, NON-DATA descriptor found
[ BOOMTOWN ]: <__main__.Foo object at 0x102b06fd0>
[ INSPECTING ]: <class '__main__.Foo'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Uno'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Dos'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Basic'>
yep, in Class.__dict__
nope, not a DATA descriptor
nope, not in instance.__dict__
yep, in Class.__dict__
yep, NON-DATA descriptor found
<class '__main__.Foo'>
Given this mixins.py
file:
class Boom(object):
def log(self):
print "[ BOOMTOWN ]: %s" % (self.__repr__())
class Basic(object):
def log(self):
print self.__class__
class Uno(Basic):
pass
class Dos(Basic):
pass
Simulate object.__getattribute__
:
from mixins import *
def object_getattribute(instance, klass, attrname, klass_mro=[]):
'''
NOTE: the resolution workflow
for Class.attrname lookups is different
'''
print "[ INSPECTING ]: %s" % klass
if attrname in klass.__dict__.keys():
print "yep, in Class.__dict__"
if ( hasattr( klass.__dict__[attrname], '__get__' )
and hasattr( klass.__dict__[attrname], '__set__' ) ):
print "yep, DATA descriptor found"
return klass.__dict__[attrname].__get__( instance, klass )
else:
print "nope, not a DATA descriptor"
else:
print "nope, not in Class.__dict__"
if attrname in instance.__dict__.keys():
print "yep, instance.__dict__"
return instance.__dict__[attrname]
else:
print "nope, not in instance.__dict__"
if attrname in klass.__dict__.keys():
print "yep, in Class.__dict__"
if hasattr( klass.__dict__[attrname], '__get__' ):
print "yep, NON-DATA descriptor found"
return klass.__dict__[attrname].__get__( instance, klass )
else:
print "return from Class.__dict__[ attrname ]"
return klass.__dict__[attrname]
else:
print "nope, not in Class.__dict__"
if hasattr( klass, '__getattr__' ):
print "return from Class.__getattr__( attrname )"
return klass.__getattr__( attrname )
else:
print "nope, no __getattr__ override"
return object_getattribute( instance,
klass_mro.pop(0), attrname, klass_mro=klass_mro )
class Foo(Uno,Dos): pass
func = object_getattribute( Foo(), Foo, 'log', klass_mro=Foo.mro()[1:] )
func()
print "\n"
class Foo(Boom,Uno,Dos): pass
func = object_getattribute( Foo(), Foo, 'log', klass_mro=Foo.mro()[1:] )
func()
print "\n"
class Foo(Uno,Boom,Dos): pass
func = object_getattribute( Foo(), Foo, 'log', klass_mro=Foo.mro()[1:] )
func()
print "\n"
class Foo(Uno,Dos,Boom): pass
func = object_getattribute( Foo(), Foo, 'log', klass_mro=Foo.mro()[1:] )
func()
print "\n"
[ INSPECTING ]: <class '__main__.Foo'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Uno'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Dos'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Basic'>
yep, in Class.__dict__
nope, not a DATA descriptor
nope, not in instance.__dict__
yep, in Class.__dict__
yep, NON-DATA descriptor found
<class '__main__.Foo'>
[ INSPECTING ]: <class '__main__.Foo'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Boom'>
yep, in Class.__dict__
nope, not a DATA descriptor
nope, not in instance.__dict__
yep, in Class.__dict__
yep, NON-DATA descriptor found
[ BOOMTOWN ]: <__main__.Foo object at 0x102b0f050>
[ INSPECTING ]: <class '__main__.Foo'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Uno'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Boom'>
yep, in Class.__dict__
nope, not a DATA descriptor
nope, not in instance.__dict__
yep, in Class.__dict__
yep, NON-DATA descriptor found
[ BOOMTOWN ]: <__main__.Foo object at 0x102b06fd0>
[ INSPECTING ]: <class '__main__.Foo'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Uno'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Dos'>
nope, not in Class.__dict__
nope, not in instance.__dict__
nope, not in Class.__dict__
nope, no __getattr__ override
[ INSPECTING ]: <class 'mixins.Basic'>
yep, in Class.__dict__
nope, not a DATA descriptor
nope, not in instance.__dict__
yep, in Class.__dict__
yep, NON-DATA descriptor found
<class '__main__.Foo'>