本文参考:廖雪峰的官方网站:https://www.liaoxuefeng.com

使用__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 "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'

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

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

使用@property

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

class Student(object):@propertydef score(self):return self._score@score.setterdef 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 = 9999
Traceback (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,bdef __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)
...
1
1
2
3
5
...
46368
75025
__getitem__

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

class Fib(object):def __getitem__(self, n):a, b = 1, 1for x in range(n):a, b = b, a + breturn 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, 1for x in range(n):a, b = b, a + breturn aif isinstance(n, slice): # n是切片start = n.startstop = n.stopif start is None:start = 0a, b = 1, 1L = []for x in range(stop):if x >= start:L.append(a)a, b = b, a + breturn 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.score
99

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

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

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

class Chain(object):def __init__(self, path=''):self._path = pathdef __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 = namedef __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@unique
class Weekday(Enum):Sun = 0 # Sun的value被设定为0Mon = 1Tue = 2Wed = 3Thu = 4Fri = 5Sat = 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

重拾Python学习(六)----------面向对象高级编程相关推荐

  1. Python学习之面向对象高级编程

    Python学习目录 1. 在Mac下使用Python3 2. Python学习之数据类型 3. Python学习之函数 4. Python学习之高级特性 5. Python学习之函数式编程 6. P ...

  2. Python基础之六面向对象高级编程

    '''面向对象高级编程 ''' from enum import Enum'''__slots__限制实例属性定义的属性只对当前类实例起作用,对于继承的子类不起作用''' class Student( ...

  3. 侯捷C++学习记录-面向对象高级编程上

    目标: 培养正规的.大气的编程习惯 以良好的方式编写C++ class [Object Based(基于对象)] 学习Classes 之间的关系 [Object Oriented(面向对象)] 继承( ...

  4. 侯捷C++学习记录-面向对象高级编程下

    本章谈到三大函数.stack堆.heap栈和内存管理. new 操作 与 delete 操作,最后对String类实现进行复习. 学习static 关键字及类模板涉及到的设计模式有:单例模式.Adap ...

  5. Python学习之面向对象编程

    Python学习目录 在Mac下使用Python3 Python学习之数据类型 Python学习之函数 Python学习之高级特性 Python学习之函数式编程 Python学习之模块 Python学 ...

  6. Python学习笔记:面向对象高级编程(完)

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  7. Python学习笔记:面向对象高级编程(中下)

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  8. Python学习笔记:面向对象高级编程(中上)

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  9. Python学习笔记:面向对象高级编程(上)

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

最新文章

  1. 5G NGC — 会话管理模型 — 边缘业务本地分流
  2. zen3架构_Zen3架构移动版CPU基准测试成绩泄露,IPC性能大增
  3. python 示例_是Python中带有示例的关键字
  4. oracle的临时表和With As总结
  5. linux windows死机,linux死机的处理方式
  6. JAVA加载 编译 运行,在Java 7中编译的加载/运行类6
  7. JAVA笔试题常见坑_java笔试常见的选择题(坑你没商量)
  8. MoSonic:对SubSonic的分布式存储、缓存改进方案尝试(1)
  9. STM32单片机驱动步进电机—简单篇
  10. java-工具-开源
  11. Python数据分析练习
  12. 切尔西为切赫提供新岗位 蓝军盼其“回家”
  13. IDEA 解决import类飘红
  14. 百度网盘限速解决方案--motrix
  15. 思科ASA防火墙:控制防火墙不让访问指定网站
  16. 【实战篇】37 # 如何使用 QCharts 图表库绘制常用数据图表?
  17. %llu 64位无符号%d、%u、%x/%X、%o%f、%e/%E或%g/%G
  18. NODE_npm发布轮子
  19. vim之vim忽略大小写查找字符串
  20. 在Matlab上用API调用chatgpt模型

热门文章

  1. 专访邦盛科技CEO王新宇:实时智能决策驱动“热数据” 价值绽放 | 爱分析访谈
  2. 初遇初识初知接下来是什么_初识爱|《傲慢与偏见》书评
  3. python安全渗透笔记
  4. PyTorch:train模式与eval模式的那些坑
  5. 数据库连接报错:connection is being used
  6. 数据分析师培训机构带你3分钟快速入门数据分析
  7. 数据表数据迁移——复制一个表的数据到另外一个表
  8. 全新的Unity移动游戏优化解决方案
  9. 浙大版《C语言程序设计实验与习题指导(第4版)》题目集 实验10-1 圆形体体积计算器
  10. 51单片机超声波测距带语音播报(源程序+原理图+原理图讲解)