【问题标题】:Pythonic way of inheriting many classes?继承许多类的Pythonic方式?
【发布时间】:2014-04-16 13:34:54
【问题描述】:

为了以更 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 类中调用水果类。例如

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 类 init 传递给 Juice 类的 fruit_name 字符串,然后使用例如:

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

我很欣赏上述所有方法在理论上可行,尽管我正在寻找开发高效编码风格的建议。在实践中,我想将此应用于不涉及水果的更复杂的项目,尽管该示例包含了我面临的许多问题。

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

【问题讨论】:

标签: python class oop inheritance


【解决方案1】:

我认为您的第一个选项最接近一个好主意,但这里有一个改进:

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)

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

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 的糖克数(即百分比)。

【讨论】:

    【解决方案2】:

    另一种思考方式是使用三个实体FruitJuiceJuicerJuicer负责获取某个Fruit,并创建一个对应类型Orange => OrangeJuiceJuice。然后你可以有两个类的层次结构,Orange 继承自 FruitOrangeJuice 继承自 JuiceJuicer 本质上是它们之间的映射。

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

    【讨论】:

    • 我认为juicerslicer 应该是函数,而不是类,(或FoodProcessor 的方法!)但我喜欢这个主意!
    • 我认为我提出这些是为了展示具有类型系统的函数式语言如何解决此类问题的颠覆性尝试。所以JuicerSlicer 实际上只是类型集之间的A=>B 态射映射。你可以在Python 中定义这些函数。但是没有什么能阻止您严格应用 OOP 模型并获得相同的结果。
    【解决方案3】:

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

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

    在 Python 3 中

    super().__init__(fruit,name)
    

    现在回答你的第二个问题。作曲你去这里的方式。果汁是由 Fruits 组成的,但它不是他创造它们的地方

    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)
    

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

    【讨论】:

      猜你喜欢
      • 2011-04-14
      • 1970-01-01
      • 1970-01-01
      • 2020-03-04
      • 1970-01-01
      • 2010-11-08
      • 2022-10-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多