Python 什么';如果子类是由构造逻辑决定的,那么将类的逻辑与其父类的逻辑分开的最简洁、最优雅的方法是什么?

Python 什么';如果子类是由构造逻辑决定的,那么将类的逻辑与其父类的逻辑分开的最简洁、最优雅的方法是什么?,python,class,inheritance,Python,Class,Inheritance,我想从字符串中构造类,比如“redapple”。这将创建类Apple的实例,它是Fruit的子类。问题是,颜色属性应该属于水果,而不是苹果。因此,在我看来,创建对象的自然方式似乎是: 解析字符串 创建水果(color=“red”) 创建Apple() 以某种方式使它成为一个单一的实体 到目前为止,我有3种选择: 一切都变成了参数 class Fruit(object): def __init__(self, color): self.color = color

我想从字符串中构造类,比如
“redapple”
。这将创建类
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")
    
  • 最简单的方法:替换
    \uuuuu类

    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
    之类的参数,而第三种方法处理这些参数要优雅得多。然而,改变
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
    听起来就像是在为。有没有更好的方法来实现目标,或者我最好使用其中一种方法


    更新:我可能必须指出,在现实生活中,
    水果
    苹果
    的初始值设定项应该设置的属性数量是可变的,总共大约15个。

    我会将创建逻辑完全从类中拉出:

    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()
    
  • 解析字符串
  • 确定要创建的对象
  • 创建对象
  • 因此,使用以下代码:

    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
    类都需要更新,本质上限制了扩展它的任何简单方法。如果您正在设计一个我想要的库,我不能重用水果,因为我不能添加香蕉、橘子或任何你没有的水果,而不改变你的代码,这与代码重用是对立的。

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

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


    从我的评论来看,我也对您的基类实例化子类型持怀疑态度。
    Fruit
    是否应该知道其所有子类型(例如,请参见答案)?

    Fruit是否应该提供构造函数?也许基类应该是一个bass类,应该有某种facxtory来稳定正确的水果类型,那么水果根本不需要知道子类。我只是认为调用fruit.fromstring()将是制作水果的一种很好的方法。不,Fruit不需要注意儿童。“我可能必须指出,在现实生活中,
    Fruit
    Apple
    的初始值设定者应该设置的属性数量是可变的,总共大约15个。”-这是一种主要的代码气味。为什么要在初始化时设置15个属性?你能把你的问题扩展得更接近“现实生活”吗?我相信你在寻找一个工厂函数,它类似于
    fromstring
    ,只是你不会让它成为放射性香蕉的
    Fruit
    +1的成员(我投票是因为逻辑分离,而不是香蕉)看起来您只是简单地将我的类方法移到了类之外:P我想知道为什么这比其他方法更可取。@squirrel我更新了代码,讨论了为什么将代码从Fruit类中删除。dm03514也是如此。@LegoStormtroopr阅读你的答案,我意识到我问这个问题有多么糟糕(我认为它几乎完美)。我忘了指出水果的数量是可变的,并不真正取决于苹果或香蕉。这意味着以您的方式(无疑是最好的方式)完成这项工作需要制作一个参数字典,以便
    Appale
    \uuuu init\uuuu
    ,后者必须决定哪些参数是他的,哪些属于Fruit的初始值设定项。但我想我没办法。谢谢,对我糟糕的提问技巧表示歉意:)每个水果都需要并将有一个颜色,输入字符串的某些部分将是统一的。乐高的想法本质上是方法#1,但它需要传递两次
    color
    (实际上,传递的参数数量可变,最多可达10个),嗯,这只是一个评论还是一个问题的答案?也就是说,传递变量是一种方法?