面向对象高级编程
正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性。
使用__slots__
Python允许在定义class的时候,定义一个特殊的__slots__
变量,来限制该class实例能添加的属性。
class student(object): __slots__ = ('name','age') #用tuple定义允许绑定的属性名称 s=student() #创建一个student实例,并给他绑定参数 s.name='wxy' s.age=20 s.source=98 print(s.name,s.age,s.source) 输出: Traceback (most recent call last): File "/home/wangxy/PycharmProjects/LearnPython/sample/oop-advanced/slots.py", line 7, in <module> s.source=98 AttributeError: 'student' object has no attribute 'source'
使用@property
有没有既能检查参数,又可以用类似属性这样简单的方式来访问类的变量呢?对于追求完美的Python程序员来说,这是必须要做到的!
还记得装饰器(decorator)可以给函数动态加上功能吗?对于类的方法,装饰器一样起作用。Python内置的@property
装饰器就是负责把一个方法变成属性调用的:
class stu(object): @property #python 内置装饰器,负责把一个getter方法变成属性调用 def score(self): return self._score @score.setter #property本身创造的另一个装饰器score.setter def score(self,value): #传入对象,值 if not isinstance(value,int): #检查值的数据类型是否为int raise ValueError('sroce must be an integer') #raise语句可以触发异常,如果value不是int则触发参数异常 if value<0 or value>100: raise ValueError('score must between 0 ~ 100!') self._score=value s=stu() s.score=60 print(s.score)
还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性:
#使用property定义一个只读属性 class vip(object): @property def birth(self): return self._birth @birth.setter def birth(self,value): self._birth=value #age只定义getter方法,不定义setter方法就是只读属性 @property def age(self): return 2017-self._birth
#练习:请利用@property给一个Screen对象加上width和height属性,以及一个只读属性resolution: class screen(object): @property def width(self): return self._width @width.setter def width(self,value): if not isinstance(value,int): raise ValueError('width must be an integer') self._width=value @property def high(self): return self._high @high.setter def high(self, value): if not isinstance(value, int): raise ValueError('high must be an integer') self._high = value @property def resolution(self): return self._width * self._high # 测试: s = screen() s.width = 1024 s.high = 768 print('resolution =', s.resolution) if s.resolution == 786432: print('测试通过!') else: print('测试失败!')
多重继承
通过多重继承,一个子类就可以同时获得多个父类的所有功能。
在设计类的继承关系时,通常,主线都是单一继承下来的,例如,Ostrich
继承自Bird
。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让Ostrich
除了继承自Bird
外,再同时继承Runnable
。这种设计通常称之为MixIn。
class Animal(object): pass #定义哺乳动物大类 class Mammal(Animal): pass #定义鸟类大类 class Bird(Animal): pass #定义动物功能类 class RunnableMixIn(object): def run(self): print("Running……") #定义动物功能飞 class FlyableMixIn(object): def fly(self): print("Flying……") #定义动物生活习惯吃肉 class CarnivorousMixIn(object): pass #定义动物生活习惯吃草 class HerbivoresMixIn(object): pass #使用多重继承定义一个多功能类 class dog(Mammal,RunnableMixIn,CarnivorousMixIn): pass d=dog() d.run()
由于Python允许使用多重继承,因此,MixIn就是一种常见的设计。
只允许单一继承的语言(如Java)不能使用MixIn的设计。
定制类
使用枚举类(http://www.cnblogs.com/ucos/p/5896861.html)
为枚举类型定义一个class类型,然后,每个常量都是class的一个唯一实例。Python提供了Enum
类来实现这个功能:
#对Enum的第一种使用 from enum import Enum month=Enum('month',('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')) for name,member in month._member_map_.items(): print(name, '=>', member, ',', member.value) 输出: Jan => month.Jan , 1 Feb => month.Feb , 2 Mar => month.Mar , 3 Apr => month.Apr , 4 May => month.May , 5 Jun => month.Jun , 6 Jul => month.Jul , 7 Aug => month.Aug , 8 Sep => month.Sep , 9 Oct => month.Oct , 10 Nov => month.Nov , 11 Dec => month.Dec , 12
#如果需要更精准的控制枚举类型,可以从Enum类生出自定义类 @unique class Weekday(Enum): Sun = 0 # Sun的value被设定为0 Mon = 1 Tue = 2 Wed = 3 Thu = 4 Fri = 5 Sat = 6 #既可以用成员名称引用枚举常量,又可以直接根据value的值获得枚举常量。 print(Weekday.Mon.value) print(Weekday(3))