[TOC]
新旧类问题
python2.2后引入了新式类,即显示继承自object的类,为了兼容旧式(经典)类,不显示继承的默认次采用旧式类方式;
python3.x 中已经完全去除经典类模式,默认全部采用新式类方式,无论是否显示继承自object。
旧式类
不满足单调性
如果类C,查找某个属性时,A排在B的前面,那么C的所有子类也要保证这个顺序
使用深度优先搜索方法调用顺序(MRO method resolution order)
不满足本地调用优先级(即根据继承顺序广度依次搜索)
如果C(A,B), 本地优先级就是需要按照声明顺序,先找A,再找B
新式类
采用C3算法,C3原本是为Lisp写的
C3引入了MRO概念,python中任意对象都可以查看起mro,例如:str.mro()
- 判断mro要先确定一个线性序列,然后查找路径由由序列中类的顺序决定。所以C3算法就是生成一个线性序列。
- 如果继承至一个基类:
class B(A)
这时B的mro序列为[B,A] - 如果继承至多个基类
class B(A1,A2,A3 …)
这时B的mro序列 mro(B) = [B] + merge(mro(A1), mro(A2), mro(A3) …, [A1,A2,A3]) - merge操作就是C3算法的核心。
遍历执行merge操作的序列,如果一个序列的第一个元素,是其他序列中的第一个元素,或不在其他序列出现,则从所有执行merge操作序列中删除这个元素,合并到当前的mro中;
merge操作后的序列,继续执行merge操作,直到merge操作的序列为空;
如果merge操作的序列无法为空,则说明不合法
元类及其应用
“元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。” —— Python界的领袖 Tim Peters
一个不错的文章
python 中万物皆可攀(对象),类class 也是对象,类是创建实例的时候申明的,而元类就是为了创建类而申明的,可以简单理解为类的类;
在我们写下如下代码时,python 解释器会查找是否含有__metaclass__
属性,如果有就使用改属性定义的函数或者元类去创建这个类,没有就会使用默认python内置的type元类去创建;
1 | class SomeClass(object): |
那么元类是在什么时候,去调用了__new__
方法去创建这个类的呢,如下
1 | # 1.类由type创建,创建类时,type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法) |
在python中,type就是造物主,万象皆是由type而来,比如:
1 | def fun(): |
如下我们定义了一个mymeta方法,在创建类A的时候会使用我们自定义的方法去创建,当然自定义的方法最终也要返回使用type去创建,毕竟人家是官方的
1 | def mymeta(class_name, class_bases, class_attr): |
单例模式
几种方式实现单例模式
使用元类可以轻松实现单例模式,单例模式的好处:
- 节约内存,所有实例话的变量应用的都是同一块内存
- 统一管理
1 | import threading |
迭代器、生成器、可迭代对象
先说可迭代对象,任何可以用iter函数调用的对象,都是可以迭代的,换言之,这个对象里面实现了__iter__
或者__getitem__
所有的容器都实现了至少其中一种方法
迭代器,实现了next方法的可迭代对象都是迭代器
生成器,实现了next方法外,又实现了send方法,return next yielded value or raise StopIteration
故而,生成器是一种特殊的迭代器,可以控制
进程间通信
单工、半双工、全双工
说到通信,无论什么方式的通信,无非分为这三种:单工、半双工、全双工
单工
单工,指在通信全程内线路的端点只能为接受方或发送方,信号只能从单一方向传输,例如:电视,广播
半双工
半双工,指在通信的某一时刻,线路中只有一个信号流,从发送方流向接受方,但是双方可以角色互换,可以互相发,但是不能同时发,比如:对讲机
全双工
全双工,指线路中任意时刻的信号流都是双向的,双方互为接受方和发送方,比如:电话
管道
最早的UNIX中的通信方式,如下PIPE 使用python实现,管道是半双工的,两端在开启时既可以是读端,也可以是写端
1 | import os, sys |
管道只能用与亲缘关系进程间通信,不能用于没有关系的两个进程通信;
数据无格式;
<1>当写端存在时,管道中没有数据时,读取管道时将阻塞
<2>当读端请求读取的数据大于管道中的数据时,此时读取管道中实际大小的数据
<3>当读端请求读取的数据小于管道中的数据时,此时放回请求读取的大小数据
<4>当写端不存在,读取管道将返回0
<5>当写端存在多个,读取管道将阻塞
<6>当写入数据超过限制(一般是系统一个页大小),写入将阻塞
FIFO
先进先出,有名管道,解决了pipe只能在亲缘进程间通信的问题, c实现方式
1 |