4

我想从字符串构造类,例如"red apple". 这将创建 class 的一个实例Apple,它是 的子类Fruit。问题是,color属性应该属于Fruit,而不是Apple。因此,在我看来,创建对象的自然方式是:

  1. 解析字符串
  2. 创造Fruit(color="red")
  3. 创造Apple()
  4. 以某种方式使其成为一个单一的实体

到目前为止,我有 3 个选项:

  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, 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")
    
  2. 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")
    
  3. 最直接的方法:替换__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 个。

4

3 回答 3

8

我会将创建逻辑完全从类中提取出来:

  1. 解析字符串
  2. 确定要创建的对象
  3. 创建对象

所以使用以下代码:

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")

编辑:回复您对 dm03514 答案的评论。

此代码与您的“选项 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,因为我不能添加香蕉、橙子或任何你没有的水果,而不改变你的代码,这与代码重用是对立的。

于 2013-09-24T01:07:35.703 回答
3

我认为您需要评估基类代表什么。

每个水果都需要颜色吗(您的observe函数会建议它至少需要一个默认值才能在调用时不会导致错误)?如果是这样,它应该是水果构造函数的一部分,并且应该被要求创建水果。

根据我的评论,我也对您的基类实例化子类型持怀疑态度。是否应该Fruit了解它的所有子类型(例如参见乐高答案)?

于 2013-09-24T01:11:15.047 回答
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()
于 2013-09-24T01:02:33.210 回答