python中的类可以基于传递的参数表现得像指定的类吗?

时间:2015-03-16 19:48:20

标签: python

我有一个抽象基类(下面称为Shape)。我从中派生了几个类(下面有CircleSquare)。

我想创建一个“调度类”(下面称为MagicShape),这样当我实例化这个新类的新对象时,它会根据传递的参数神奇地成为上面的派生类之一。

即。如果CircleSquare都使用2个参数初始化,我希望MagicShape在实例化时获取3个参数,以便第一个参数可以是字符串circle或字符串square会导致使用随后指定的参数创建CircleSquare

所以对于细节,我有:

from numpy import pi as PI

class Shape(object):
    def __init__(self, color, size):
        self.color=color
        self.size = size

    def describe(self):
        return 'I am a {color:s} {kind:s} of size {size:0.1f}'.format(color=self.color, 
                                                                      kind=self.kind,
                                                                      size=self.size)

class Circle(Shape):
    def __init__(self, color, size):
        self.kind = 'circle'
        super(Circle, self).__init__(color, size)

    def area(self):
        return PI * self.size * self.size

class Square(Shape):
    def __init__(self, color, size):
        self.kind = 'square'
        super(Square, self).__init__(color, size)

    def area(self):
        return self.size * self.size

我希望有类似的东西:

class MagicShape(???):
    def __init__(self, kind, color, size):
        # what goes in here?

因此,当我运行ms = MagicShape('circle', 'red', 3)时,msCircle,但当我运行ms = MagicShape('square', 'blue', 2)时,msSquare。< / p>

我知道我可以这样做:

def make_shape(kind, color, size):
    if 'circle'==kind:
        return Circle(color, size)
    elif 'square'==kind:
        return Square(color, size)
    else:
        raise ValueError

并通过功能执行“调度”。但不知怎的,这感觉它应该适用于课程。有人可以让我直截了当吗?

4 个答案:

答案 0 :(得分:4)

你可以使用一个函数,不需要任何类:

shapes = {shape.__name__.lower(): shape 
          for shape in Shape.__subclasses__()}

def MagicShape(kind, color, size):
    try:
        return shapes[kind](color, size)
    except KeyError:
        raise ValueError(kind)

此处class.__subclasses__() method会返回Shape的所有子类,从而可以快速方便地构建从kind字符串到类的映射。

请记住,创建一个类只是另一个调用。之间没有区别:

class Foo(object):
    def __init__(self, arg1, arg2):
        pass

def Foo(arg1, arg2):
    return something_that_is_an_instance
从来电者的角度来看;他们只是使用:

result = Foo(value1, value2)

用于类和函数。

答案 1 :(得分:0)

您想使用工厂模式,此示例几乎完全符合您的要求: http://python-3-patterns-idioms-test.readthedocs.org/en/latest/Factory.html

答案 2 :(得分:0)

您可能想要做的事情(工厂/派遣功能)已在此处的其他答案/评论中列出,但如果您确实想要返回其他类实例并使其看起来像您一样。只使用MagicClass,您可以使用__new__方法做一些花哨/糟糕的事情,如下所示:

class MagicClass(object):
    def __new__(cls, *args, **kwargs): 
        # if args[whatever] == 'square': return Square(*args, **kwargs)

......或类似的东西。这不是一个好习惯,但它可行的。

答案 3 :(得分:0)

您想使用工厂方法。就像你一样,但你可以把它拉到超级Shape类下。

from numpy import pi as PI

class Shape(object):
    #we'll use this below factory method to return the correct subclass:
    @classmethod
    def getShape(self,kind,color,size):
        if 'circle'==kind:
            return Circle(color, size)
        elif 'square'==kind:
            return Square(color, size)
        else:
           raise ValueError

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

    def describe(self):
        return 'I am a {color:s} {kind:s} of size {size:0.1f}'.format(color=self.color, 
                                                                      kind=self.kind,
                                                                      size=self.size)

class Circle(Shape):
    def __init__(self, color, size):
        self.kind = 'circle'
        super(Circle, self).__init__(color, size)

    def area(self):
        return PI * self.size * self.size

class Square(Shape):
    def __init__(self, color, size):
        self.kind = 'square'
        super(Square, self).__init__(color, size)

    def area(self):
        return self.size * self.size