继承:‘是一个’的关系
假设我们决定开一家餐厅。我们需要做的其中一件事就是聘请员工为顾客服务、准备食物,等等。工程师是核心,我们决定创造一个做饭机器人,但是为了符合逻辑,我们也决定把机器人做成有薪水的功能齐全的员工。
饭店团队可以通过文件employees.py中的四个类来定义。最通用的类Employee提供共同行为,例如,加薪(giveRaise)和打印(__str__)。员工有两种,所以Employee有两个子类:Chef和Server。这两个子类都会覆盖继承的work方法来打印更具体的信息。最后,我们的机器人是由更具体的类来模拟:Robot是一种Chef,也是一种Employee。以OOP术语来看,我们称这些关系为“是一个”(is-a)链接:机器人是一个主厨,而主厨是一个员工。以下是employees.py文件。
<code>class
Employee
:def
__init__
(
self
,name,salary=0
):self
.name=nameself
.salary=salarydef
giveRaise
(
self
,percent) :self
.salary=self
.salary*(1
+percent)def
work
(
self
): print(self
.name,'does stuff'
)def
__str__
(
self
):return
'Employee:%s,%d'
%(self.name,self.salary)
class
Chef
(Employee
):def
__init__
(
self
,name): Employee.__init__
(self
,name,50000
)def
work
(
self
): print(self
.name,'makes food'
)class
Server
(Employee
):def
__init__
(
self
,name): Employee.__init__
(self
,name,40000
)def
work
(
self
): print(self
.name,'does service'
)class
Robot
(Chef
):def
__init__
(
self
,name): Chef.__init__
(self
,name)def
work
(
self
): print(self
.name,'Robot is working!'
)if
__name__
=='__main__'
:for
Kclassin
(Employee,Chef,Server,Robot): obj=Kclass(Kclass.__name__
) obj.work() Employee does stuff Chef makes food Server does service Robot Robot is working!/<code>
组合:‘有一个’的关系
既然我们已经有了员工,就把他们放到饭店,开始忙吧。我们的店是一个组合对象,有个烤炉,也有服务生和主厨这些员工。当顾客来店下单时,店里的组件就会开始行动:服务生接下订单,主厨制作比萨,等等。下面的例子(文件foodshop.py)模拟了这个场景中所有的对象和关系。
<code>class
Customer
:def
__init__
(
self
,name,food_list):self
.name=nameself
.food_list=food_listdef
order
(
self
,server): print('%s is serving for %s,the food he order is %s'
%(server.name,self.name,str(self.food_list)
))def
pay
(
self
,server): print('%s has paid to %s'
%(self.name,server.name)
)class
Oven
:def
bake
(
self
): print('The oven is baking!'
)class
Foodshop
:def
__init__
(
self
):self
.server=Server('John'
)self
.chef=Robot('Bob'
)self
.oven=Oven()def
Order
(
self
,name): customer=Customer(name,['tea'
,'soup'
]) customer.order(self
.server)self
.chef.work()self
.oven.bake() customer.pay(self
.server)if
__name__
=='__main__'
: aaa=Foodshop() aaa.Order('shunge'
) John is servingfor
shunge,the food he order is ['tea'
,'soup'
] Bob Robot is working! The oven is baking! shunge has paid to John/<code>
OOP与委托
面向对象时常会谈到所谓的委托(delegation),通常就是指控制器对象内嵌其他对象,而把运算请求传给那些对象。控制器负责管理工作,例如,记录存取等。在Python中,委托通常是以__getattr__方法实现的,因为这个方法会拦截对不存在属性的读取,包装类(有时称为代理类)可以使用__getattr__把任意读取转发给被包装的对象。包装类包有被包装对象的接口,而且自己也可以增加其他运算。例:跟踪打印消息
<code>class
trace
:def
__init__
(
self
,obj):self
.obj=obj
def
__getattr__
(
self
,attrname): print('Trace:'
,attrname)return
getattr(self
.obj,attrname) x=trace([1
,2
,3
,4
,5
]) x.append(5
) output:Trace:
append/<code>
类的伪私有属性
Python程序员用一个单个的下划线来编写内部名称(例如,_X),这只是一个非正式的惯例,让你知道这是一个不应该修改的名字(它对Python自身来说没有什么意义)。
但更通用的方法是变量名前面加上两个下划线,比如Person类中的__salary,会自动扩展为_Person__salary,这样就避免了和其他类所创建的类似变量名冲突。
<code>class
Person
:def
__init__
(self,name)
: self.__name=name a=Person('shunge'
) print(a.__dict__) a.__name='shun'
print(a.__name,a._Person__name) output:{'_Person__name'
:'shunge'
} shun shunge /<code>