博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
重拾Python学习(六)----------面向对象高级编程
阅读量:4126 次
发布时间:2019-05-25

本文共 5540 字,大约阅读时间需要 18 分钟。

本文参考:

使用__slots__

果我们想要限制实例的属性,比如,只允许对Student实例添加name和age属性。

class Student(object):    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称

定义一个特殊的__slots__变量,来限制该class实例能添加的属性:

>>> s = Student() # 创建新的实例>>> s.name = 'Michael' # 绑定属性'name'>>> s.age = 25 # 绑定属性'age'>>> s.score = 99 # 绑定属性'score'Traceback (most recent call last):  File "
", line 1, in
AttributeError: 'Student' object has no attribute 'score'

对继承的子类是不起作用的:

>>> class GraduateStudent(Student):...     pass...>>> g = GraduateStudent()>>> g.score = 9999

使用@property

装饰器(decorator)可以给函数动态加上功能,对于类的方法,装饰器一样起作用。Python内置的@property装饰器就是负责把一个方法变成属性调用的:

class Student(object):    @property    def score(self):        return self._score    @score.setter    def score(self, value):        if not isinstance(value, int):            raise ValueError('score must be an integer!')        if value < 0 or value > 100:            raise ValueError('score must between 0 ~ 100!')        self._score = value

把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值

>>> s = Student()>>> s.score = 60 # OK,实际转化为s.set_score(60)>>> s.score # OK,实际转化为s.get_score()60>>> s.score = 9999Traceback (most recent call last):  ...ValueError: score must between 0 ~ 100!

多重继承

在设计类的继承关系时,通常,主线都是单一继承下来的,但是,如果需要“混入”额外的功能,通过多重继承就可以实现,这种设计通常称之为MixIn。

class Dog(Mammal, RunnableMixIn, CarnivorousMixIn):    pass

举个例子,Python自带了TCPServerUDPServer这两类网络服务,而要同时服务多个用户就必须使用多进程或多线程模型,这两种模型由ForkingMixInThreadingMixIn提供

class MyTCPServer(TCPServer, ForkingMixIn):    pass
class MyUDPServer(UDPServer, ThreadingMixIn):    pass

定制类

__slots__我们已经知道怎么用了,__len__()方法我们也知道是为了能让class作用于len()函数。

Python的class中还有许多这样有特殊用途的函数,可以帮助我们定制类。

__str__

打印一个实例:

>>> class Student(object):...     def __init__(self, name):...         self.name = name...     def __str__(self):...         return 'Student object (name: %s)' % self.name...>>> print(Student('Michael'))Student object (name: Michael)

【注】不用print,打印出来的实例:

>>> s = Student('Michael')>>> s<__main__.Student object at 0x109afb310>

这是因为直接显示变量调用的不是__str__(),而是__repr__(),两者的区别是__str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串,也就是说,__repr__()是为调试服务的。(解决: __repr__ = __str__

__iter__

一个类想被用于for ... in循环,类似list或tuple那样,就必须实现一个__iter__()方法,该方法返回一个迭代对象。Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。

class Fib(object):    def __init__(self):        self.a, self.b = 0, 1 # 初始化两个计数器a,b    def __iter__(self):        return self # 实例本身就是迭代对象,故返回自己    def __next__(self):        self.a, self.b = self.b, self.a + self.b # 计算下一个值        if self.a > 100000: # 退出循环的条件            raise StopIteration()        return self.a # 返回下一个值
>>> for n in Fib():...     print(n)...11235...4636875025
__getitem__

要表现得像list那样按照下标取出元素,需要实现__getitem__()方法:

class Fib(object):    def __getitem__(self, n):        a, b = 1, 1        for x in range(n):            a, b = b, a + b        return a
>>> f = Fib()>>> f[0]1>>> f[1]1>>> f[2]2>>> f[3]3>>> f[10]89>>> f[100]573147844013817084101

新增切片方法:

class Fib(object):    def __getitem__(self, n):        if isinstance(n, int): # n是索引            a, b = 1, 1            for x in range(n):                a, b = b, a + b            return a        if isinstance(n, slice): # n是切片            start = n.start            stop = n.stop            if start is None:                start = 0            a, b = 1, 1            L = []            for x in range(stop):                if x >= start:                    L.append(a)                a, b = b, a + b            return L
>>> f = Fib()>>> f[0:5][1, 1, 2, 3, 5]>>> f[:10][1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

没有对step参数作处理,也没有对负数作处理,所以,要正确实现一个__getitem__()还是有很多工作要做的

__getattr__

正常情况下,当我们调用类的方法或属性时,如果不存在,就会报错,要避免这个错误,除了可以加上这个属性外,写一个__getattr__()方法,动态返回一个属性

class Student(object):    def __init__(self):        self.name = 'Michael'    def __getattr__(self, attr):        if attr=='score':            return 99

当调用不存在的属性时,比如score,Python解释器会试图调用__getattr__(self, 'score')来尝试获得属性

>>> s = Student()>>> s.name'Michael'>>> s.score99

只有在没有找到属性的情况下,才调用__getattr__,已有的属性,比如name,不会在__getattr__中查找。

这实际上可以把一个类的所有属性和方法调用全部动态化处理了,不需要任何特殊手段。这种完全动态调用的特性有什么实际作用呢?作用就是,可以针对完全动态的情况作调用。

利用完全动态的__getattr__,我们可以写出一个链式调用:

class Chain(object):    def __init__(self, path=''):        self._path = path    def __getattr__(self, path):        return Chain('%s/%s' % (self._path, path))    def __str__(self):        return self._path    __repr__ = __str__
>>> Chain().status.user.timeline.list'/status/user/timeline/list'

如果要写SDK,给每个URL对应的API都写一个方法,那得累死,而且,API一旦改动,SDK也要改。这样,无论API怎么变,SDK都可以根据URL实现完全动态的调用,而且,不随API的增加而改变!

__call__

当我们调用实例方法时,我们用instance.method()来调用,只需要定义一个__call__()方法,就可以直接对实例进行调用

class Student(object):    def __init__(self, name):        self.name = name    def __call__(self):        print('My name is %s.' % self.name)

调用方式如下:

>>> s = Student('Michael')>>> s() # self参数不要传入My name is Michael.

使用枚举类

Python提供了Enum类来实现每个常量都是class的一个唯一实例

from enum import EnumMonth = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))

更精确地控制枚举类型,可以从Enum派生出自定义类:

from enum import Enum, unique@uniqueclass Weekday(Enum):    Sun = 0 # Sun的value被设定为0    Mon = 1    Tue = 2    Wed = 3    Thu = 4    Fri = 5    Sat = 6

@unique装饰器可以帮助我们检查保证没有重复值。

>>> day1 = Weekday.Mon>>> print(day1)Weekday.Mon>>> print(Weekday.Tue)Weekday.Tue>>> print(Weekday['Tue'])Weekday.Tue>>> print(Weekday.Tue.value)2>>> print(day1 == Weekday.Mon)True>>> print(day1 == Weekday.Tue)False>>> print(Weekday(1))Weekday.Mon>>> print(day1 == Weekday(1))True

转载地址:http://tuhpi.baihongyu.com/

你可能感兴趣的文章
好书分享之——《能力陷进》
查看>>
阅读笔记《c++ primer》
查看>>
阅读笔记《C++标准程序库》
查看>>
基于mirror driver的windows屏幕录像
查看>>
C语言8
查看>>
Qt实现简单延时
查看>>
qml有关矩形说明
查看>>
在qt中使用QSplitter设置初始比例setStretchFactor失效的解决方法
查看>>
repeater的使用
查看>>
qt msvc编译中文乱码解决
查看>>
qt中TextField输入框无法输入中文解决办法
查看>>
qt实现点击出现窗口,点击其他任何地方窗口消失
查看>>
QML DropArea拖拉文件事件
查看>>
CORBA links
查看>>
读后感:&gt;
查看>>
ideas about sharing software
查看>>
different aspects for software
查看>>
To do list
查看>>
Study of Source code
查看>>
如何使用BBC英语学习频道
查看>>