面向对象高级编程

正常情况下,当我们定义了一个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))

 

使用元类

 

posted @ 2017-12-06 17:09  wangxy92  阅读(178)  评论(0编辑  收藏  举报