为了用更加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
我很欣赏上述所有内容在理论上都有效,尽管我正在寻找建立有效编码风格的建议。在实践中,我想将其应用于一个不涉及水果的更复杂的项目,尽管这个例子涵盖了我面临的许多问题。
欢迎所有建议/提示/建议阅读链接。感谢。
答案 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)
考虑这一点的另一种方法是使用三个实体Fruit
,Juice
和Juicer
。 Juicer
负责获取某个Fruit
并创建相应类型Juice
的{{1}}。然后,您可以拥有两个层次的类,Orange => OrangeJuice
继承自Orange
,Fruit
继承自OrangeJuice
,Juice
基本上映射它们。
这可以解决您提出的解决方案会产生的许多棘手问题。例如,如果我有一个名为Juicer
的类消耗了一些Slicer
,则产生Fruit
(FruitSalad
)。在您提出的抽象中,我可以给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)
我认为这也回答了你的第三个问题。