文章目录
- 1.协议
- 2.定制序列
- 3.迭代器
- 4.生成器
1.协议
- •协议(Protocols)与其他编程语言中的接口很相似,它规定你哪些方法必须要定义。然而,在Python中的协议就显得不那么正式。事实上,在Python中,协议更像是一种指南。
2.定制序列
- 容器类型的协议
- 如果说你希望定制的容器是不可变的话,你只需要定义__len__()和__getitem__()魔法方法。
- 如果你希望定制的容器是可变的话,除了__len__()和__getitem__()方法,你还需要定义__setitem__()和__delitem__()两个魔法方法。
- 定制容器类相关的魔法方法
魔法方法 | 含义 |
__ len__(self) | 定义当被len()函数调用时的行为(返回容器中元素的个数) |
__ getitem__(self, value) | 定义获取容器中指定元素的行为,相当于self[key] |
__ setitem__(self, key, value) | 定义设置容器中指定元素的行为,相当于self[key]=value |
__ delitem__(self, key) | 定义删除容器中指定元素的行为,相当于del self[key] |
__ iter__(self) | 定义当迭代容器中的元素的行为 |
__ reversed__(self) | 定义当被reversed()函数调用时的行为 |
__ contains__(self, item) | 定义当使用成员测试运算符(in或not in)时的行为 |
- | - |
- eg:编写一个不可改变的自定义列表,要求记录列表中每个元素被访问的次数。
class CountList: #定义记录列表中每个元素访问次数类
def __init__(self,*args): #参数是可变类型的
self.values = [x for x in args]#将args的数据存入列表self.values中
self.count = {}.fromkeys(range(len(self.values)),0)#创建字典,存放每一个下标所放的对应次数
def __len__(self): #返回容器中元素的个数
return len(self.values)#len方法用于返回参数的长度
def __getitem__(self,key): #获取容器中指定元素的行为,key为访问对应的键
self.count[key] += 1#每访问一次,字典键对应的键值加1
return self.values[key]
>>> c1 = CountList(1,3,5,7,9)
>>> c2 = CountList(2,4,6,8,10)
>>> c1[1] #c1[1]第一次访问
3
>>> c2[2]
6
>>> c1[1] + c2[2] #c1[1]第二次访问
9
>>> c1.count
{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
>>> c2.count
{0: 0, 1: 0, 2: 2, 3: 0, 4: 0}
- Python基于序列的三大容器类指的是什么?
答:列表(List)、元组(Tuple)、字符串(String)。 - 如果你想要定制一个不可变的容器,你就不能定义像__ setitem__()和__ delitem__()方法,这两个会修改容器中的数据的方法
- 如果希望定制的容器支持reversed()内置方法,那么你应该定义什么方法?
答:应该定义__ reversed__()方法,提供对内置函数reversed()的支持。 - 既然是容器,必须要提供能够查询“容器”的方法,那么请问需要定义什么方法呢?
答:在Python中,我们通过len()内置函数来查询容器的“容量”,所以容器应该定义__ len__()方法。 - 通过定义哪些方法使得容器支持读、写和删除的操作?
答:读是__ getitem__();写是__ setitem__();删除时__ delitem__()。
3.迭代器
- 迭代的意思类似于循环,每一次重复的过程被称为一次迭代的过程,而每一次迭代得到的结果会被用来作为下一次迭代的初始值。提供迭代方法的容器称为迭代器(如序列(列表、元组、字符串)、字典,文件等)。
- eg:
- 对一个容器对象调用iter()就得到它的迭代器,调用next()迭代器就会返回下一个值。若迭代器没有值可以返回了,就会抛出异常。
•iter()
魔法方法:–__iter__(),实际上返回迭代器本身self
•next()
魔法方法:–__next__(),这里写迭代的规律。
- eg:
>>> string = "FishC"
>>> it = iter(string)
>>> next(it)
'F'
>>> next(it)
'i'
>>> next(it)
's'
>>> next(it)
'h'
>>> next(it)
'C'
>>> next(it)
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
next(it)
StopIteration
for和while循环实际上用的是迭代器
string="FishC"
it = iter(string)
while True:
try:
each=new(it)
except StopIteration:
break;
print(each)
F
i
s
h
C
for each in string:
print(each)
F
i
s
h
C
- 一个容器如果是迭代器,那就必须实现__iter__()魔法方法,这个方法实际上就是返回迭代器本身。重点要实现的是__next__()魔法方法,因为它决定了迭代的规则。
>>> class Fibs:
def __init__(self):
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
##下面的代码可以简写为: self.a,self.b = self.b,self.a + self.b
### return self.a
self.c = self.a + self.b
self.a = self.b
self.b = self.c
return self.c
>>> fibs = Fibs()
>>> for each in fibs:
if each < 20:
print(each)
else:
break
1
1
2
3
5
8
13
class Fibs:
def __init__(self, n=20):
self.a = 0
self.b = 1
self.c = 0
self.n = n
def __iter__(self):
return self
def __next__(self):
self.c = self.a + self.b
self.a = self.b
self.b = self.c
if self.a > self.n:
raise StopIteration
return self.c
fibs = Fibs(20)
for each in fibs:
print(each)
- 迭代器需要我们定义一个类,去实现相应的方法才可以定义一个灵活的迭代器
4.生成器
- 所谓协同程序,就是可以运行的独立函数调用,函数可以暂停或者挂起,并在需要的时候从程序离开的地方继续或者重新开始。
生成器可以暂时挂起函数,并保留函数的局部变量等数据,然后在再次调用它的时候,从上次暂停的位置继续执行下去。
一个函数中如果有yield语句,则被定义为生成器。 - 生成器是迭代器的一种实现,是特殊的迭代器
- 函数结束可以用异常,return,或者所有语句都执行完毕
- eg:
>>> def myGen():
print("生成器被执行了!")
yield 1 #暂停一次,相当于return,返回1
yield 2 #暂停一次,相当于return,返回2
>>> myG = myGen()
>>> next(myG)
生成器被执行了!
1
>>> next(myG)
2
>>> next(myG)
Traceback
XXX
StopIteration
>>> for i in myGen():
print(i)
- eg像前面介绍的斐波那契的例子,也可以用生成器来实现:
>>> def fibs():
a = 0
b = 1
while True:
a,b = b,a + b
yield a
>>> for each in fibs():
if each > 100:
break
print(each, end = ' ' )
- 列表推导式表达:
100以内,能被2整除,但不能被3整除的所有整数
>>> a = [i for i in range(100) if not (i % 2) and (i % 3 )]
>>> a
[2, 4, 8, 10, 14, 16, 20, 22, 26, 28, 32, 34, 38, 40, 44, 46, 50, 52, 56, 58, 62, 64, 68, 70, 74, 76, 80, 82, 86, 88, 92, 94, 98]
- 字典推导式:
10以内是否为偶数
>>> a = {i:i % 2 == 0 for i in range(10)}
>>> a
{0: True, 1: False, 2: True, 3: False, 4: True, 5: False, 6: True, 7: False, 8: True, 9: False}
- 集合推导式:
不会有重复的
>>> a = {i for i in [1,2,3,3,4,5,5,5,6,7,7,8]}
>>> a
{1, 2, 3, 4, 5, 6, 7, 8}
- 元组生成器推导式:
>>> e = (i for i in range(5))
>>>e
generator object <genexpr> at 0x02F1FE68
>>> next(e)
0
>>> next(e)
1
>>> next(e)
2
>>>sum(i for i in range(100) if i % 2)
2500
>>>sum((i for i in range(100) if i % 2))
2500
- 生成器的深入阅读
- 参考:小甲鱼零基础入门学习python笔记,第四十七课:魔法方法:定制序列