我想从"red apple"
等字符串构造类。这将创建一个类Apple
的实例,它是Fruit
的子类。问题是,color
属性应该属于Fruit
,而不属于Apple
。因此,在我看来,创建对象的自然方式是:
Fruit(color="red")
Apple()
到目前为止,我有3个选项:
一切都变成了参数
class Fruit(object):
def __init__(self, color):
self.color = color
def observe(self):
print "Looks like a tasty %s fruit" % self.color
@classmethod
def fromstring(cls, string):
color, kind = string.split()
if kind == "apple":
return Apple(color)
class Apple(Fruit):
def __init__(self, *args, **kwargs):
super(Apple, self).__init__(*args, **kwargs)
self.tasty = True
def bite(self):
print "I bite into a tasty apple"
fruit = Fruit.fromstring("red apple")
color
属性从外部填写
class Fruit(object):
def observe(self):
print "Looks like a tasty %s fruit" % self.color
@classmethod
def fromstring(cls, string):
color, kind = string.split()
if kind == "apple":
ins = Apple()
ins.color = color
return ins
class Apple(Fruit):
def __init__(self):
self.tasty = True
def bite(self):
print "I bite into a tasty apple"
fruit = Fruit.fromstring("red apple")
最简单的方法:替换__class__
class Fruit(object):
def __init__(self, string):
self.color, kind = string.split()
if kind == "apple":
self.__class__ = Apple
Apple.__init__(self)
def observe(self):
print "Looks like a tasty %s fruit" % self.color
class Apple(Fruit):
def __init__(self):
self.tasty = True
def bite(self):
print "I bite into a tasty apple"
fruit = Fruit("red apple")
运行
fruit.observe()
fruit.bite()
print type(fruit), fruit.tasty
给出相同的输出:
Looks like a tasty red fruit
I bite into a tasty apple
<class '__main__.Apple'> True
第一种方法,可以说是最通用的方法,需要传递诸如color
之类的参数,这些参数在第三种方法中处理得更为优雅。然而,改变__class__
听起来像是使用高级工具来完成一项平凡的任务。是否有更好的方法来实现目标,或者我最好使用其中一种?
更新:我可能必须指出,在现实生活中,Fruit
和Apple
的初始值设定项应设置的属性数量为变量,总共约15个。
答案 0 :(得分:8)
我会完全从类中拉出创建逻辑:
所以使用以下代码:
class Fruit(object):
def __init__(self, color):
self.color = color
def observe(self):
print "Looks like a tasty %s fruit" % self.color
class Apple(Fruit):
def __init__(self,color):
super(Apple, self).__init__(color)
self.tasty = True
def bite(self):
print "I bite into a tasty apple"
fruit = None
color,type = "red apple".split()
if type == "apple":
fruit = Apple(color)
if type == "banana" and color == "blue"
raise Exception("Welcome to Chernobyl")
此代码与您的“选项1”之间的主要区别在于,Fruit
不需要了解其子类。在我的代码中,我可以这样做:
class Banana(Fruit):
def __init__(self,color):
if color not in ["yellow","green"]:
raise Exception("Welcome to Chernobyl")
super(Banana).__init__(self,color)
if color = "yellow":
self.ripe = True
elif color = "green:"
self.ripe = False
def bite(self):
print "I bite into a %s banana"%["unripe","ripe"][self.ripe]
Fruit
不需要我的子类知识。在您的代码中,对于每种新类型的水果,Fruit
类都需要更新,实质上限制了任何扩展它的简单方法。如果您正在设计我想要的库,我无法重复使用Fruit,因为我无法添加香蕉,橙色或任何没有的水果而不会更改代码这是对立的代码重用。
答案 1 :(得分:3)
我认为你需要评估基类代表什么。
每个水果都需要一种颜色(你的observe
函数会建议它至少需要一个默认值,如果它被调用则不会导致错误)?如果是这样,它应该是水果构造者的一部分,应该被要求创造一个水果。
从我的评论中,我也对你的基类实例化子类型持怀疑态度。 Fruit
是否应该了解其所有子类型(例如,请参阅legos答案)?
答案 2 :(得分:1)
class Fruit(object):
def __init__(self,color):
self.color = color
def observe(self):
print "Looks like a tasty %s fruit" % self.color
@classmethod
def fromstring(cls, my_string):
color, kind = my_string.split()
my_class = globals().get(kind.capitalize(),Fruit)(color)
assert isinstance(my_class, Fruit),"Error Unknown Kind %s"%kind
return my_class
class Apple(Fruit):
def __init__(self,color):
self.tasty = True
Fruit.__init__(self,color)
def bite(self):
print "I bite into a tasty apple"
a = Fruit.fromstring("red apple")
print a
a.bite()