================================================================================
Python和OOP
Python的OOP实现与Java类似,可以概括为三个概念:
1.【继承】继承是基于Python中的属性查找(在X.name表达式中)
2.【多态】在X.method方法中,method的意义取决于X的类型
3.【封装】方法和运算符实现行为,数据隐藏默认是一种惯例
================================================================================
OOP和继承:“是一个”关系
举例说明:披萨店团队可以通过文件employees.py中的四个类来定义。最通用的类Employee提供共同行为,例如,加薪(giveRaise)和打印(__repr__)。员工有两种,所以Employee有两个子类:Chef和Server(厨师和服务员)。这两个子类都会覆盖继承的work方法来打印更具体的信息。最后,披萨机器人是由更具体的类来模拟:PizzaRobot是一种Chef,也是一种Employee。以OOP术语来看,这些关系为“是一个”(is-a)链接:机器人是一个主厨,而主厨是一个员工。代码编写如下:
#File employees.py class Employee: def __init__(self,name,salary = 0): self.name = name self.salary = salary def giveRaise(self,percent): self.salary = self.salary + (self.salary * percent) def work(self): print(self.name,'does stuff') def __repr__(self): return '<Employee : name = %s , salary = %s>'%(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,'interfaces with customer') class PizzaRobot(Chef): def __init__(self,name): Chef.__init__(self,name) def work(self): print(self.name,'makes pizza') if __name__ == '__main__': bob = PizzaRobot('bob') print(bob) bob.work() bob.giveRaise(.2) print(bob) print() for klass in Employee,Chef,Server,PizzaRobot: obj = klass(klass.__name__) obj.work()运行结果如下:
<Employee : name = bob , salary = 50000> bob makes pizza <Employee : name = bob , salary = 60000.0> Employee does stuff Chef makes food Server interfaces with customer PizzaRobot makes pizza可以看到,bob是一个PizzaRobot,但是打印的时候,依然显示是Employee,从结果看不出他具体属于哪一类员工,这时候可以修改Employee类中的__repr__方法如下:
def __repr__(self): return '<%s : name = %s , salary = %s>'%(self.__class__.__name__,self.name,self.salary)其中,self.__class__.__name__,可以返回实例所属类的名称,修改之后执行结果如下:
<PizzaRobot : name = bob , salary = 50000> bob makes pizza <PizzaRobot : name = bob , salary = 60000.0> Employee does stuff Chef makes food Server interfaces with customer PizzaRobot makes pizza================================================================================
OOP和组合:“有一个”关系
组合涉及把其他对象嵌入容器对象内,并使用其容器方法。组合反映了各组成部分之间的关系,通常称为“有一个”(has-a)关系。
接着上边的例子,既然我们已经有了员工,就把他们放到我们披萨店。披萨店是一个组合对象,有个烤炉,也有服务员和主厨这些员工。当顾客来店里下单时,店里的组件就会开始行动:服务员接单,主厨制作披萨,等等。看下边的例子pizzashop.py.
#File pizzashop.py from employees import PizzaRobot,Server class Customer: def __init__(self,name): self.name = name def order(self,server): print(self.name,'orders from',server) def pay(self,server): print(self.name,'pays for item to',server) class Oven: def bake(self): print('oven bakes') class PizzaShop: def __init__(self): self.server = Server('Pat') #组合其他对象 self.chef = PizzaRobot('Bob') #一个名叫Bob的机器人主厨 self.oven = Oven() def order(self,name): customer = Customer(name) customer.order(self.server) self.chef.work() self.oven.bake() customer.pay(self.server) if __name__ == '__main__': scene = PizzaShop() scene.order('Homer') #模拟Homer的订单 print('...') scene.order('Shaggy') #模拟Shaggy的订单这里,PizzaShop是类的容器和控制器。当执行这个模块时,我们的披萨店处理了两份订单:一份来自Hommer,另一份来自Shaggy。
Homer orders from <Server : name = Pat , salary = 40000> Bob makes pizza oven bakes Homer pays for item to <Server : name = Pat , salary = 40000> ... Shaggy orders from <Server : name = Pat , salary = 40000> Bob makes pizza oven bakes Shaggy pays for item to <Server : name = Pat , salary = 40000>================================================================================
>>> class wrapper: def __init__(self,object): self.wrapped = object def __getattr__(self,attrname): print('Trace:',attrname) return getattr(self.wrapped,attrname)__getattr__会获得属性名称字符串。这个程序利用getattr内置函数,以变量名字符串从包裹对象取出属性:getattr(X,N)就像是X.N,只不过N是表达式,可在运行时计算出字符串,而不是变量。事实上,getattr(X,N)类似于X.__dict__[N]。
>>> x = wrapper([1,2,3]) >>> x.append(4) Trace: append >>> x.wrapped [1, 2, 3, 4] >>> >>> x = wrapper({'a':1,'b':2}) >>> x.keys() Trace: keys dict_keys(['b', 'a'])实际的效果就是以包装类内额外的代码来增强被包装的对象的整个接口。我们可以利用这种方式记录方法调用,把方法调用转给其他或定制的逻辑等。
class C1: def meth1(self):self.X = 88 def meth2(self):print(self.X)另一个程序员独立作业,也写了这样一个类,他有同样的假设:
class C2: def metha(self):self.X = 99 def methb(self):print(self.X)如果这两个类混合在相同的类树中时,问题就产生了:
class C3(C1,C2):... I = C3()因为C1和C2中的变量名都是X,所以I中只能有一个X,取决于最后一个赋值的是哪个类,这样就使得其中一个数据被无缘无故丢掉了。
>>> class C1: def meth1(self):self.__X = 88 def meth2(self):print(self.__X) >>> class C2: def metha(self):self.__X = 99 def methb(self):print(self.__X) >>> class C3(C1,C2):pass >>> I = C3() >>> I.meth1();I.metha() >>> print(I.__dict__) {'_C1__X': 88, '_C2__X': 99}这样,X属性就会扩张,从而包含它的类的名称,然后才加到实例中。查看其命名空间字典可以看到变量变成了_C1__X和_C2__X。
多重继承:“混合”类
在class语句中,首行括号内可以列出一个以上的超类。当这么做时,就是在使用所谓的【多重继承】。
搜索属性时,Python会由左至右搜索首行中的超类,直到找到相符者。
通常来说,多重继承是建模属于一个集合以上的对象的好办法。例如,一个人可以是工程师、作家、音乐家等,因此,可继承这些集合的特性。
================================================================================
类是对象:通用对象的工厂
>>> def factory(aClass,*args): return aClass(*args) >>> class Spam: def doit(self,message): print(message) >>> class Person: def __init__(self,name,job): self.name = name self.job = job >>> obj1 = factory(Spam) >>> obj2 = factory(Person,'Guido','gurr')在这段代码中, 我们定义了一个对象生成器函数,称为factory。它预期传入的是类对象,还有该类构造函数的一个或多个参数。
原文:http://blog.csdn.net/gavin_john/article/details/50729802