在实例化的超类的python中进行子类化

时间:2015-11-01 14:28:44

标签: python inheritance subclass

是否可以使用已经实例化的超类在Python中进行子类化?

我并不完全知道如何构建问题所以让我举个例子。假设我有一个类Rectangle,我想构建另一个类ColoredRectangle。但我不希望每个ColoredRectangle相同的维度成为自己的新Rectangle。因此,当我发起ColoredRectangle时,我会将其传递给已经实例化的Rectangle

是的,我想要

r = Rectangle([1,2])
r_red = ColoredRectangle(r, "red")
r_blue = ColoredRectangle(r, "blue")

但现在r_redr_blue应该能够获得所有矩形方法和属性。例如,假设Rectangle具有area()属性。

r.area
2
r_red.area
2

r_redr_blue应该"指向"到同一个Rectangle。我知道我可以通过写作来做到这一点:

 class ColoredRectangle(Rectangle):

      def __init__(self, rectangle, color):
          self.color = color
          self.rectangle = rectangle

但是我必须写

  r_red.rectangle.area

这很难看。

3 个答案:

答案 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