实例化超类的python中的子类化

Ben*_*Ben 6 python inheritance subclass

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

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

即,我想要

r = Rectangle([1,2])
r_red = ColoredRectangle(r, "red")
r_blue = ColoredRectangle(r, "blue")
Run Code Online (Sandbox Code Playgroud)

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

r.area
2
r_red.area
2
Run Code Online (Sandbox Code Playgroud)

r_redr_blue应“指向”相同Rectangle。我知道我可以这样写:

 class ColoredRectangle(Rectangle):

      def __init__(self, rectangle, color):
          self.color = color
          self.rectangle = rectangle
Run Code Online (Sandbox Code Playgroud)

但是那我得写

  r_red.rectangle.area
Run Code Online (Sandbox Code Playgroud)

这很丑。

Seb*_*zny 6

遗产

继承在 Python 中是件好事,我认为您不必求助于getattrhack,如果您想要这些,请向下滚动。

您可以强制类字典引用另一个对象:

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
Run Code Online (Sandbox Code Playgroud)

这两个将引用同一个Rectangle对象:

crect.width=10
print rect.width, rect.height
#10 5
Run Code Online (Sandbox Code Playgroud)

这是关于元编程的精彩演讲,虽然它的标题暗示了 Python3,但其中很多也适用于 Python 2.x:David Beazley - Python3 元编程


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
Run Code Online (Sandbox Code Playgroud)

如果您想要不同的“代理对象”,它们可以从基础获取属性Rectangle但不会相互干扰,必须求助于getattrhacking,这也很有趣:

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)
Run Code Online (Sandbox Code Playgroud)

这将避免干扰:

kain = ColoredRectangle(eve, color="blue")
abel = ColoredRectangle(eve, color="red")
print kain.color, abel.color
#blue red
Run Code Online (Sandbox Code Playgroud)

关于__getattr____getattribute__

getattrgetattribute之间的一个主要区别是 getattr仅在未按通常方式找到属性时调用。这对于为缺少的属性实施回退很有用,并且可能是您想要的两个之一。来源

因为只有未找到的属性将由__getattr__您处理,所以您还可以部分更新您的代理,这可能会令人困惑:

kain.width=10
print eve.area(), kain.area(), abel.area()
# 15 50 15
Run Code Online (Sandbox Code Playgroud)

为避免这种情况,您可以覆盖__setattr__

def __setattr__(self, attr, value):
    if attr == "color":
        return super(ColoredRectangle,self).setattr(attr,value)
    raise YourFavoriteException
Run Code Online (Sandbox Code Playgroud)