Inheritance
Inheritance is such a nice thing in python, and I don't think you have to resort to getattr
hacks, if you want those, scroll down.
You can force the class dictionary to refer to another object:
class Rectangle(object):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class ColoredRectangle(Rectangle):
def __init__(self, rect, color):
self.__dict__ = rect.__dict__
self.color = color
rect = Rectangle(3, 5)
crect = ColoredRectangle(rect, color="blue")
print crect.width, crect.height, crect.color
#3 5 blue
These two will refer to the same Rectangle
object:
crect.width=10
print rect.width, rect.height
#10 5
This is an exellent talk on metaprogramming, and while it's title implies Python3 a lot of it also applies to python 2.x: David Beazley - Python3 Metaprogramming
getattr
hacking
If for any reason however, you would want to have multiple ColoredRectangle
refer to the same base Rectangle
then these will conflict with each other:
eve = Rectangle(3, 5)
kain = ColoredRectangle(eve, color="blue")
abel = ColoredRectangle(eve, color="red")
print eve.color, kain.color, abel.color
#red red red
If you'd like different "proxy objects", which can get attributes from the base Rectangle
but not interfere with each other, you have to resort to getattr
hacking, which is fun too:
class ColoredRectangle(Rectangle):
def __init__(self, rect, color):
self.rect = rect
self.color = color
def __getattr__(self,attr):
return getattr(self.rect,attr)
eve = Rectangle(3, 5)
This will avoid the interference:
kain = ColoredRectangle(eve, color="blue")
abel = ColoredRectangle(eve, color="red")
print kain.color, abel.color
#blue red
About __getattr__
versus __getattribute__
:
A key difference between getattr and getattribute is that
getattr is only invoked if the attribute wasn't found the usual ways. It's good for implementing a fallback for missing attributes,
and is probably the one of two you want. source
Because only non found attributes will be handled by __getattr__
you can also partially update your proxies, which might be confusing:
kain.width=10
print eve.area(), kain.area(), abel.area()
# 15 50 15
To avoid this you can override __setattr__
:
def __setattr__(self, attr, value):
if attr == "color":
return super(ColoredRectangle,self).setattr(attr,value)
raise YourFavoriteException