我有一个抽象基类(下面称为Shape
)。我从中派生了几个类(下面有Circle
和Square
)。
我想创建一个“调度类”(下面称为MagicShape
),这样当我实例化这个新类的新对象时,它会根据传递的参数神奇地成为上面的派生类之一。
即。如果Circle
和Square
都使用2个参数初始化,我希望MagicShape
在实例化时获取3个参数,以便第一个参数可以是字符串circle
或字符串square
会导致使用随后指定的参数创建Circle
或Square
。
所以对于细节,我有:
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)
时,ms
为Circle
,但当我运行ms = MagicShape('square', 'blue', 2)
时,ms
为Square
。< / p>
我知道我可以这样做:
def make_shape(kind, color, size):
if 'circle'==kind:
return Circle(color, size)
elif 'square'==kind:
return Square(color, size)
else:
raise ValueError
并通过功能执行“调度”。但不知怎的,这感觉它应该适用于课程。有人可以让我直截了当吗?
答案 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