十九、 描述符
描述符就是将某种特殊类型的类的实例指派给另一个类的属性。
所谓特殊类型, 要求至少实现以下三个方法中的一个(全部实现也可以)
__get__(self, instance, owner) 定义当描述符的值被取得时的行为
用于访问属性, 他返回属性的值
__set__(self, instance, value) 定义当描述符的值被改变时的行为
将在属性分配操作中调用, 不返回任何值
__delete__(self, instance) 定义当描述符的值被删除时的行为
控制删除操作,不返回任何内容
class MyProperty:
def __init__(self, f_get=None, f_set=None, f_del=None):
self.f_get = f_get
self.f_set = f_set
self.f_del = f_del
def __get__(self, instance, owner):
return self.f_get(instance)
def __set__(self, instance, value):
return self.f_set(instance,value)
def __delete__(self, instance):
self.f_del(instance)
class C:
def __init__(self):
self._x = None
def get_x(self):
return self._x
def set_x(self, value):
self._x = value
def del_x(self):
del self._x
x = MyProperty(get_x, set_x, del_x)
c = C()
c.x = "xiaoming"
print(c.x) xiaoming
del c.x
print(c.x) AttributeError: 'C' object has no attribute '_x'
二十、 定制序列
协议是什么?
协议与其他编程语言中的接口很相似, 它规定你哪些方法必须要定义。 然而, 在python中的协议就显得不那么正式,
事实上, 在python中, 协议更像是一种指南。
鸭子类型 : 当看到一只鸟走起来像鸭子, 游起来像鸭子, 叫起来也像鸭子, 那么这只鸟就可以被称为鸭子。
如果你希望定制的容器是不可变的话, 你只需要定义 __len__() 和 __getitem__() 方法。
如果你希望定制的容器是可变的话, 除了 __len__() 和 __getitem__() 方法,
你还需要定义 __setitem__() 和 __delitem__() 两个方法。
__len__() 方法 :
定义当被 len() 调用时的行为(返回容器中元素的个数)
__getitem__() 方法:
定义获取容器中指定元素的行为, 相当于 self[key]
__setitem__() 方法:
定义设置容器中指定元素的行为, 相当于 self[key] = value
__delitem__() 方法:
定义删除容器中指定元素的行为。 相当于 del self[key]
不可变容器 :
class CountList:
def __init__(self, *args):
self.values = [x for x in args]
self.count = {}.fromkeys(range(len(self.values)), 0)
def __len__(self):
print('你正在调用 __len__ 方法啊')
return len(self.values)
def __getitem__(self, item):
print('你正在调用 __getitem__ 方法啊')
self.count[item] += 1
return self.values[item]
count_list1 = CountList(1, 3, 5, 7, 9)
count_list2 = CountList(2, 4, 6, 8, 10)
print(count_list1[1])
你正在调用 __getitem__ 方法啊
3
print(count_list2[1])
你正在调用 __getitem__ 方法啊
4
print(count_list1[1] + count_list2[1])
你正在调用 __getitem__ 方法啊
你正在调用 __getitem__ 方法啊
7
print(count_list1.count)
{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
print(count_list2.count)
{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
count_list1[1] = 5
print(count_list1[1]) TypeError: 'CountList' object does not support item assignment
可变容器 :
class CountList:
def __init__(self, *args):
self.values = [x for x in args]
self.count = {}.fromkeys(range(len(self.values)), 0)
def __len__(self):
print('你正在调用 __len__ 方法啊')
return len(self.values)
def __getitem__(self, item):
print('你正在调用 __getitem__ 方法啊')
self.count[item] += 1
return self.values[item]
def __setitem__(self, key, value):
print('正在调用 __setitem__ 方法啊')
self.values[key] = value
def __delitem__(self, key):
print('正在调用 __delitem__ 方法啊')
del self.values[key]
count_list1 = CountList(1, 3, 5, 7, 9)
count_list1[1] = 5
正在调用 __setitem__ 方法啊
print(count_list1[1])
你正在调用 __getitem__ 方法啊
5
del count_list1[1]
正在调用 __delitem__ 方法啊
二十一、迭代器
迭代器的特点 :
迭代,顾名思义就是重复做一些事很多次(就现在循环中做的那样)。迭代器是实现了__next__()方法的对象(这个方法在调用时不需要任何参数),
它是访问可迭代序列的一种方式,通常其从序列的第一个元素开始访问,直到所有的元素都被访问才结束。
[注意]:迭代器只能前进不能后退.
如果迭代到最后超出范围, 则抛出 : StopIteration
迭代器需要可以被 iter() 和 next() 这两个方法调用 。 【 实现两个 __iter__() 和 __next__() 这两个魔法方法 】
创建迭代器 :
a、 使用内建的工厂函数iter(iterable)可以将可迭代序列转换为迭代器
a = [1, 2, 3, 4]
print(type(a)) <class 'list'>
print(next(a)) TypeError: 'list' object is not an iterator
print(type(iter(a))) <class 'list_iterator'>
print(next(iter(a))) 1
b、 自定义迭代器。
由于Python中没有“迭代器”这个类,因此具有以下两个特性的类都可以称为“迭代器”类:
1、有__next__()方法,返回容器的下一个元素或抛出StopIteration异常
2、有__iter__()方法,返回迭代器本身
class Fibs:
def __init__(self, n):
self.a = 0
self.b = 1
self.n = n
def __iter__(self):
return self
def __next__(self):
self.a, self.b = self.b, self.a + self.b
if self.a > self.n:
raise StopIteration
return self.a
for each in Fibs(30):
print(each)
输出 : 1 1 2 3 5 8 13 21
二十二、 生成器
所谓的协调程序就是可以运行的独立的函数调用, 函数可以暂停或者挂起, 并在需要的时候从程序离开的地方继续或者重新开始。
对于普通的函数, 一般都是从函数的第一行开始执行, 知道所有的行都执行完毕或者遇到 return 函数才结束。
一旦函数将控制权交还给调用者, 函数里面的一切都结束了。
而 【生成器】 是一个特殊的【函数】, 调用可以在中断、停止。 暂停之后, 他把控制权临时交出来,
然后下次调用再接着上次离开的地方继续执行。
生成器关键字 : 【 yield 】
def my_gen():
print('生成器执行了。。。')
yield 1 【 第一次调用在这里结束】
yield 2 【 第二次调用从这里开始】
mg = my_gen()
print('-'*50)
print(next(mg))
print('-'*50)
print(next(mg))
输出 :
--------------------------------------------------
生成器执行了。。。
1
--------------------------------------------------
2
生成器实现 斐波那契 :
def fibs():
a = 0
b = 1
while True:
a, b = b, a + b
yield a
for each in fibs():
if each > 30:
break
print(each)
输出 : 1 1 2 3 5 8 13 21