是否可以使用已经实例化的超类在Python中进行子类化?
我并不完全知道如何构建问题所以让我举个例子。假设我有一个类Rectangle,我想构建另一个类ColoredRectangle。但我不希望每个ColoredRectangle
相同的维度成为自己的新Rectangle
。因此,当我发起ColoredRectangle
时,我会将其传递给已经实例化的Rectangle
。
r = Rectangle([1,2])
r_red = ColoredRectangle(r, "red")
r_blue = ColoredRectangle(r, "blue")
但现在r_red
和r_blue
应该能够获得所有矩形方法和属性。例如,假设Rectangle
具有area()
属性。
r.area
2
r_red.area
2
r_red
和r_blue
应该"指向"到同一个Rectangle
。我知道我可以通过写作来做到这一点:
class ColoredRectangle(Rectangle):
def __init__(self, rectangle, color):
self.color = color
self.rectangle = rectangle
但是我必须写
r_red.rectangle.area
这很难看。
答案 0 :(得分:4)
您似乎要做的是将属性访问重定向到基础Rectangle
对象。 __getattr__
方法可以为您完成此操作。
class ColoredRectangle(object):
def __init__(self, rectangle, color):
self.color = color
self.rectangle = rectangle
def __getattr__(self,attr):
return getattr(self.rectangle,attr)
答案 1 :(得分:4)
继承在python中是一件好事,我认为你不必诉诸getattr
黑客,如果你想要那些,请向下滚动。
您可以强制类字典引用另一个对象:
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
这两个将引用相同的Rectangle
对象:
crect.width=10
print rect.width, rect.height
#10 5
这是一个关于元编程的优秀演讲,虽然它的标题暗示了Python3,但很多它也适用于python 2.x: David Beazley - Python3 Metaprogramming
getattr
黑客攻击如果出于任何原因,您希望多个ColoredRectangle
引用相同的基础Rectangle
,那么这些将相互冲突:
eve = Rectangle(3, 5)
kain = ColoredRectangle(eve, color="blue")
abel = ColoredRectangle(eve, color="red")
print eve.color, kain.color, abel.color
#red red red
如果您想要不同的“代理对象”,它们可以从基座Rectangle
获取属性但不会相互干扰,那么 到诉诸getattr
黑客,这也很有趣:
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)
这样可以避免干扰:
kain = ColoredRectangle(eve, color="blue")
abel = ColoredRectangle(eve, color="red")
print kain.color, abel.color
#blue red
关于__getattr__
与__getattribute__
:
getattr 和 getattribute 之间的主要区别在于 只有在找不到常用方法的属性时,才会调用 getattr 。这对于实现缺少属性的后备是有好处的, 并且可能是你想要的两个中的一个。 source
由于__getattr__
只会处理未找到的属性,因此您也可以部分更新代理,这可能会造成混淆:
kain.width=10
print eve.area(), kain.area(), abel.area()
# 15 50 15
为避免这种情况,您可以覆盖__setattr__
:
def __setattr__(self, attr, value):
if attr == "color":
return super(ColoredRectangle,self).setattr(attr,value)
raise YourFavoriteException
答案 2 :(得分:0)
通过矩形属性编写所有属性。它们位于__dict__
属性中。
import copy
class Rectangle(object):
def __init__(self, area):
self.area = area
class ColoredRectangle(Rectangle):
def __init__(self, rectangle, color):
self.__dict__ = copy.deepcopy(rectangle.__dict__)
self.color = color