Pythonic继承许多类的方式?

时间:2014-04-16 13:34:54

标签: python class oop inheritance

为了用更加python和OOP风格的方式编写代码,我想知道是否有人可以建议我实现这个概念。

让我们说我有一个水果的基类,比如苹果和香蕉,它包含了该类的基本属性,例如:颜色。然后我想分类继承自称为果汁的水果,它增加了方法和属性,例如体积,糖。

粗略的结构可能是:

class Fruit(object):
def __init__(self, fruit_name):
    if fruit_name == 'apple': 
        self.color = 'green'
        self.sugar_content = 2
    elif fruit_name == 'banana':
        self.color = 'yellow'
        self.sugar_content = 3

然后我继承了我的Fruit类的方法:

class Juice(Fruit):
    def __init___(self, fruit_name, volume, additives):
        PERHAPS I NEED TO USE A SUPER STATEMENT HERE TO PASS THE fruit_name parameter (which is 'apple' or 'banana' BACK TO THE FRUIT CLASS? I want this class to be able to access sugar_content and color of the the fruit class.
        self.volume = volume
        self.additives = additives

    def calories(self, sugar_added):
        return sugar_added + 2*self.sugar_content* self.volume # i.e. some arbitrary function using the class parameters of both this juice class and the original fruit class

所以最终,我可以创建一个像:

这样的对象
my_juice = Juice(fruit_name='apple', volume=200, additives='sugar,salt')
print 'My juice contains %f calories' % self.calories(sugar_added=5)
print 'The color of my juice, based on the fruit color is %s' % self.color

另外,我想知道最好不要继承并简单地从Juice类中调用fruit类。 e.g。

class Juice(object):
    def __init__(self, fruit_name, volume, additives):
        self.fruit = Fruit(fruit_name=fruit_name)
        self.volume = volume # ASIDE: is there an easier way to inherit all parameters from a init call and make them into class variables of the same name and accessible by self.variable_name calls?
        self.additives = additives

    def calories(self, sugar_added):
        return sugar_added + 2*self.fruit.sugar_content* self.volume

在某些方面,上面的感觉比self更自然.Fruit.sugar_content直接表明sugar_content是水果的属性。如果我继承了,那么我会使用self.sugar_content,这是水果的属性,虽然可能与果汁类的糖含量相混淆,这取决于其他因素。

或者,最好还是为每个水果分别创建一个类,并将逻辑语句用于评估传递给Juice类的fruit_name字符串,如果在Juice类 init 中,然后使用eg:

class Apple(object):
   self.color = 'green'

class Banana(object):
    self.color = 'yellow'

class Juice(object):
    def __init__(self, fruit_name, other params):
         if fruit_name == 'apple':
             self.Fruit = Apple
             self.sugar_content=2
         elif fruit_name == 'banana':
             self.Fruit = Banana
             self.sugar_content=3
         # Or some easier way to simply say
             self.Fruit = the class which has the same name as the string parameter fruit_name

我很欣赏上述所有内容在理论上都有效,尽管我正在寻找建立有效编码风格的建议。在实践中,我想将其应用于一个不涉及水果的更复杂的项目,尽管这个例子涵盖了我面临的许多问题。

欢迎所有建议/提示/建议阅读链接。感谢。

3 个答案:

答案 0 :(得分:4)

我认为你的第一个选择最接近一个好主意,但这是一个改进:

class Fruit:

    def __init__(self, name, sugar_content):
        self.name = name
        self.sugar_content = sugar_content

现在,确定每个Fruit包含多少糖的逻辑完全移出了类定义之外。哪里可以去?一个选项是子类:

class Apple(Fruit):

    def __init__(self):
        super().__init__("apple", 2)

或者,如果Fruit之间的唯一区别是名称和糖含量,只需创建实例并输入数据(例如从文件中):

apple = Fruit("apple", 2)

现在Juice怎么样?这是由 Fruit组成的,但实际上并不是Fruit,因此继承并不适合。尝试:

class Juice:

    def __init__(self, fruits):
        self.fruits = fruits

    @property
    def sugar_content(self):
        return sum(fruit.sugar_content for fruit in self.fruits)

您可以传递可迭代的Fruit个实例来制作Juice

>>> mixed_fruit = Juice([Fruit("apple", 2), Fruit("banana", 3)])
>>> mixed_fruit.sugar_content
5

然后,您可以将其扩展为包含以下想法:

  • 每个Fruit多少进入Juice;
  • Juice的体积是多少(从成分计算的另一个@property?);和
  • 存在哪些添加剂(水,糖等)。

以一致的比例单位工作是明智的,例如:每克sugar_content以克为单位Fruit(即百分比)。

答案 1 :(得分:3)

考虑这一点的另一种方法是使用三个实体FruitJuiceJuicerJuicer负责获取某个Fruit并创建相应类型Juice的{​​{1}}。然后,您可以拥有两个层次的类,Orange => OrangeJuice继承自OrangeFruit继承自OrangeJuiceJuice基本上映射它们。

这可以解决您提出的解决方案会产生的许多棘手问题。例如,如果我有一个名为Juicer的类消耗了一些Slicer,则产生FruitFruitSalad)。在您提出的抽象中,我可以给Fruit[] => FruitSalad Slicer个实例(您建议将其作为OrangeJuice的一种类型)并期望它吐出一个美味的Fruit,而不是所有我得到的是一个潮湿的柜台。

答案 2 :(得分:2)

概念上Juice不应该继承Fruit,但是为了你的问题,让我们假设这样做是有道理的。在您的第一个代码示例中,必须调用

super(Juice,self).__init__(fruit,name)

在Python 3中将是

super().__init__(fruit,name)

现在回答你的第二个问题。作品 就像你走到这里一样。果汁由水果组成,但它不是他创造它们的地方

class Juice(object):
    def __init__(self, fruit, volume, additives):
        self.fruit = fruit
        self.volume = volume
        self.additives = additives

这样你就可以:

apple = Apple(...)
apple_juice= Juice(apple,2,None)

我认为这也回答了你的第三个问题。