实例化超类的python子类化

2024-06-28 22:02:05 发布

您现在位置:Python中文网/ 问答频道 /正文

有没有可能在Python中使用已经实例化的超类生成子类?在

我不知道该如何界定这个问题,所以让我举个例子。假设我有一个类矩形,我想构建另一个类coloredlectangle。但我不希望相同维度的每个ColoredRectangle都是自己的新Rectangle。所以当我启动ColoredRectangle时,我会传递一个已经实例化的Rectangle。在

也就是说,我想要

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

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

^{pr2}$

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

 class ColoredRectangle(Rectangle):

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

但那我就得写了

  r_red.rectangle.area

很难看。在


Tags: 实例self属性areabluered子类例子
3条回答

您似乎要求做的是将属性访问重定向到底层的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)

按矩形属性写入所有属性。它们在__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

继承

继承在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对象:

^{pr2}$

这是一篇关于元编程的优秀演讲,虽然它的标题意味着Python3,但它的很多内容也适用于python2.x:David Beazley - Python3 Metaprogramming


getattr黑客攻击

但是,如果出于任何原因,您希望多个ColoredRectangle引用同一个基Rectangle,那么这些将相互冲突:

^{3}$

如果您希望不同的“代理对象”,它们可以从基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__与{}:

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

由于只有未找到的属性将由__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

相关问题 更多 >