Skip to main content
Code Review

Return to Question

Bumped by Community user
Bumped by Community user
replaced http://stackoverflow.com/ with https://stackoverflow.com/
Source Link

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?

Fix copy&paste indentation, markup.
Source Link
ferada
  • 11.4k
  • 25
  • 65

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'>
Tweeted twitter.com/StackCodeReview/status/661014729301823489
edited tags
Link
jonrsharpe
  • 14k
  • 2
  • 36
  • 62
edited tags
Link
200_success
  • 145.5k
  • 22
  • 190
  • 478
Loading
Source Link
Loading
lang-py

AltStyle によって変換されたページ (->オリジナル) /