在__init__设置一个对象的超类?

时间:2009-12-08 14:19:00

标签: python oop

在实例化对象时,是否有可能传入一个对象应该派生自的类?

例如:

class Red(object):
    def x(self):
        print '#F00'

class Blue(object):
    def x(self):
        print '#00F'

class Circle(object):
    def __init__(self, parent):
        # here, we set Bar's parent to `parent`
        self.x()

class Square(object):
    def __init__(self, parent):
        # here, we set Bar's parent to `parent`
        self.x()
        self.sides = 4

red_circle = Circle(parent=Red)
blue_circle = Circle(parent=Blue)
blue_square = Square(parent=Blue)

其效果类似:

class Circle(Red):
    def __init__(self):
        self.x()
但是,

不影响Circle的其他实例。

5 个答案:

答案 0 :(得分:7)

也许您正在寻找的是一个班级工厂:

#!/usr/bin/env python
class Foo(object):
    def x(self):
        print('y')

def Bar(parent=Foo):
    class Adoptee(parent):
        def __init__(self):
            self.x()
    return Adoptee()
obj=Bar(parent=Foo)

答案 1 :(得分:4)

我同意@AntsAasma。您应该考虑使用dependency injection。至少在给出的示例中(我肯定会大大简化以说明您的问题),通过has-a relationship而不是is-a relationship来更好地表示形状的颜色。

您可以通过将所需的颜色对象传递给构造函数,存储对它的引用以及将函数调用委托给此对象来实现此目的。这极大地简化了实现,同时仍保留了所需的行为。请看这里的例子:

class Red(object):
    def x(self):
        print '#F00'

class Blue(object):
    def x(self):
        print '#00F'

class Shape(object):
    def __init__(self,color):
        self._color=color
    def x(self):
        return self._color.x()

class Circle(Shape):
    def __init__(self, color):
        Shape.__init__(self,color)
        self.x()

class Square(Shape):
    def __init__(self, color):
        Shape.__init__(self,color)
        self.x()
        self.sides = 4

red_circle = Circle(color=Red())
blue_circle = Circle(color=Blue())
blue_square = Square(color=Blue())

编辑:修复了示例代码中构造函数参数的名称

答案 2 :(得分:1)

听起来你正试图将继承用于不适合的事情。如果您想解释为什么要这样做,可能会找到一种更加惯用且有效的方法来实现您的目标。

答案 3 :(得分:0)

如果你真的需要它,那么你可以使用type构造函数,例如在工厂函数内(或在__new__方法内,但这可能是更安全的方法):

class Foo(object):
    def x(self):
        print 'y'

class Bar(object):
    def __init__(self):
        self.x()

def magic(cls, parent, *args, **kwargs):
    new = type(cls.__name__, (parent,), cls.__dict__.copy())
    return new(*args, **kwargs)

obj = magic(Bar, parent = Foo)

答案 4 :(得分:0)

正如其他人所说,这是一个非常奇怪的用法,但是,如果你真的想要它,它肯定是可行的(除了神秘的Bar,你在评论中茫然;-)。例如:

class Circle(object):
    def __init__(self, parent):
        self.__class__ = type('Circle', (self.__class__, parent), {})
        self.x()

这为Circle的每个实例提供了自己的个人类(全部名为Circle,但都不同) - 这部分实际上是这个成语有时非常有用的关键原因(当你想要一个使用新式类的“每实例自定义特殊方法”:由于特殊方法总是在类上查找,要按实例自定义它,您需要每个实例都有一个不同的类! - )。如果您希望尽可能多地进行类共享,您可能需要一些备忘录工厂功能来帮助:

_memo = {}
def classFor(*bases):
  if bases in _memo: return _memo[bases]
  name = '_'.join(c.__name__ for c in bases)
  c = _memo[bases] = type(name, bases, {})
  return c

(这里我也使用不同的方法来生成类的名称,使用Circle_RedCircle_Blue等类名作为示例,而不仅仅是Circle)。然后:

class Circle(object):
    def __init__(self, parent):
        self.__class__ = classFor(Circle, parent)
        self.x()

所以这项技术非常流畅,但我仍然认为它与你举例说明的用例不相符。但是,它可能在其他用例中很有用,所以我正在展示它。