Python3基础教程(十六)—— 迭代器、生成器、装饰器
在这个实验里我们学习迭代器、生成器、装饰器有关知识。
这几个概念是 Python 中不容易理解透彻的概念,务必把所有的实验代码都完整的输入并理解清楚其中每一行的意思。
迭代器
Python 迭代器(Iterators)对象在遵守迭代器协议时需要支持如下两种方法:
__iter__()
,返回迭代器对象自身。这用在for
和in
语句中。__next__()
,返回迭代器的下一个值。如果没有下一个值可以返回,那么应该抛出StopIteration
异常。
class Counter(object):
def __init__(self, low, high):
self.current = low
self.high = high def __iter__(self):
return self def __next__(self):
#返回下一个值直到当前值大于 high
if self.current > self.high:
raise StopIteration
else:
self.current += 1
return self.current - 1
现在我们能把这个迭代器用在我们的代码里。
>>> c = Counter(5,10)
>>> for i in c:
... print(i, end=' ')
...
5 6 7 8 9 10
请记住迭代器只能被使用一次。这意味着迭代器一旦抛出 StopIteration
,它会持续抛出相同的异常。
>>> c = Counter(5,6)
>>> next(c)
5
>>> next(c)
6
>>> next(c)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in next
StopIteration
>>> next(c)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in next
StopIteration
我们已经看过在 for
循环中使用迭代器的例子了,下面的例子试图展示迭代器被隐藏的细节:
>>> iterator = iter(c)
>>> while True:
... try:
... x = iterator.__next__()
... print(x, end=' ')
... except StopIteration as e:
... break
...
5 6 7 8 9 10
生成器
生成器(Generators)是更简单的创建迭代器的方法,这通过在函数中使用 yield
关键字完成:
>>> def my_generator():
... print("Inside my generator")
... yield 'a'
... yield 'b'
... yield 'c'
...
>>> my_generator()
<generator object my_generator at 0x7fbcfa0a6aa0>
在上面的例子中我们使用 yield
语句创建了一个简单的生成器。我们能在 for
循环中使用它,就像我们使用任何其它迭代器一样。
>>> for char in my_generator():
... print(char)
...
Inside my generator
a
b
c
在下一个例子里,我们会使用一个生成器函数完成与 Counter 类相同的功能,并且把它用在 for 循环中。
>>> def counter_generator(low, high):
... while low <= high:
... yield low
... low += 1
...
>>> for i in counter_generator(5,10):
... print(i, end=' ')
...
5 6 7 8 9 10
在 While 循环中,每当执行到 yield
语句时,返回变量 low
的值并且生成器状态转为挂起。在下一次调用生成器时,生成器从之前冻结的地方恢复执行然后变量 low
的值增一。生成器继续 while
循环并且再次来到 yield
语句...
当你调用生成器函数时它返回一个生成器对象。如果你把这个对象传入 dir()
函数,你会在返回的结果中找到 __iter__
和 __next__
两个方法名。
我们通常使用生成器进行惰性求值。这样使用生成器是处理大数据的好方法。如果你不想在内存中加载所有数据,你可以使用生成器,一次只传递给你一部分数据。
os.path.walk() 函数是最典型的这样的例子,它使用一个回调函数和当前的 os.walk
生成器。使用生成器实现节约内存。
我们可以使用生成器产生无限多的值。以下是一个这样的例子。
>>> def infinite_generator(start=0):
... while True:
... yield start
... start += 1
...
>>> for num in infinite_generator(4):
... print(num, end=' ')
... if num > 20:
... break
...
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
如果我们回到 my_generator()
这个例子,我们会发现生成器的一个特点:它们是不可重复使用的。
>>> g = my_generator()
>>> for c in g:
... print(c)
...
Inside my generator
a
b
c
>>> for c in g:
... print(c)
...
一个创建可重复使用生成器的方式是不保存任何状态的基于对象的生成器。任何一个生成数据的含有 __iter__
方法的类都可以用作对象生成器。在下面的例子中我们重新创建了 counter
生成器。
>>> class Counter(object):
... def __init__(self, low, high):
... self.low = low
... self.high = high
... def __iter__(self):
... counter = self.low
... while self.high >= counter:
... yield counter
... counter += 1
...
>>> gobj = Counter(5, 10)
>>> for num in gobj:
... print(num, end=' ')
...
5 6 7 8 9 10
>>> for num in gobj:
... print(num, end=' ')
...
5 6 7 8 9 10
上面的 gobj
并不是生成器或迭代器,因为它不具有 __next__
方法,只是一个可迭代对象,生成器是一定不能重复循环的。 如果想要使类的实例变成迭代器,可以用 __iter__
+ __next__
方法实现:
>>> from collections import Iterator
>>> class Test():
...: def __init__(self, a, b):
...: self.a = a
...: self.b = b
...: def __iter__(self):
...: return self
...: def __next__(self):
...: self.a += 1
...: if self.a > self.b:
...: raise StopIteration()
...: return self.a
...: >>> test = Test(5, 10) >>> isinstance(test, Iterator)
True
生成器表达式
生成器表达式(Generator expressions)是列表推导式和生成器的一个高性能,内存使用效率高的推广。
举个例子,我们尝试对 1 到 9 的所有数字进行平方求和。
>>> sum([x*x for x in range(1,10)])
这个例子实际上首先在内存中创建了一个平方数值的列表,然后遍历这个列表,最终求和后释放内存。你能理解一个大列表的内存占用情况是怎样的。
我们可以通过使用生成器表达式来节省内存使用。
>>> sum(x*x for x in range(1,10))
生成器表达式的语法要求其总是直接在在一对括号内,并且不能在两边有逗号。这基本上意味着下面这些例子都是有效的生成器表达式用法示例:
>>> sum(x*x for x in range(1,10))
285
>>> g = (x*x for x in range(1,10))
>>> g
<generator object <genexpr> at 0x7fc559516b90>
我们可以把生成器和生成器表达式联系起来,在下面的例子中我们会读取文件 '/var/log/cron'
并且查看任意指定任务(例中我们搜索 'anacron'
)是否成功运行。
我们可以用 shell 命令 tail -f /etc/crontab |grep anacron
完成同样的事(按 Ctrl + C 终止命令执行)。
>>> jobtext = 'anacron'
>>> all = (line for line in open('/etc/crontab', 'r') )
>>> job = ( line for line in all if line.find(jobtext) != -1)
>>> text = next(job)
>>> text
'25 6\t* * *\troot\ttest -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )\n'
>>> text = next(job)
>>> text
'47 6\t* * 7\troot\ttest -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )\n'
>>> text = next(job)
>>> text
'52 6\t1 * *\troot\ttest -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )\n'
你可以写一个 for
循环遍历所有行。
闭包
闭包(Closures)是由另外一个函数返回的函数。我们使用闭包去除重复代码。在下面的例子中我们创建了一个简单的闭包来对数字求和。
>>> def add_number(num):
... def adder(number):
... #adder 是一个闭包
... return num + number
... return adder
...
>>> a_10 = add_number(10)
>>> a_10(21)
31
>>> a_10(34)
44
>>> a_5 = add_number(5)
>>> a_5(3)
8
adder 是一个闭包,把一个给定的数字与预定义的一个数字相加。
装饰器
装饰器(Decorators)用来给一些对象动态的添加一些新的行为,我们使用过的闭包也是这样的。
我们会创建一个简单的示例,将在函数执行前后打印一些语句。
>>> def my_decorator(func):
... def wrapper(*args, **kwargs):
... print("Before call")
... result = func(*args, **kwargs)
... print("After call")
... return result
... return wrapper
...
>>> @my_decorator
... def add(a, b):
... #我们的求和函数
... return a + b
...
>>> add(1, 3)
Before call
After call
4
参考链接:https://www.shiyanlou.com/courses/596
Python3基础教程(十六)—— 迭代器、生成器、装饰器的更多相关文章
- Python 迭代器&生成器,装饰器,递归,算法基础:二分查找、二维数组转换,正则表达式,作业:计算器开发
本节大纲 迭代器&生成器 装饰器 基本装饰器 多参数装饰器 递归 算法基础:二分查找.二维数组转换 正则表达式 常用模块学习 作业:计算器开发 实现加减乘除及拓号优先级解析 用户输入 1 - ...
- Python基础-迭代器&生成器&装饰器
本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 我现在有个需求,看 ...
- 08 . Python3高阶函数之迭代器、装饰器
Python3高阶函数之迭代器.装饰器 列表生成式 推导式就是构建比较有规律的列表,生成器. 孩子,我现在有个需求,看列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],我要求你把列表里 ...
- 迭代器/生成器/装饰器 /Json & pickle 数据序列化
本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 孩子,我现在有个需 ...
- css3基础教程十六变形与动画animation
前面我们讲过的变形与动画一般都是通过鼠标的单击.获得焦点,被点击或对元素进行一定改变后以后触发效果的,那么有没有像Flash一样自动播放的动画效果呢?答案当然是肯定的,这就是我们今天要讲到的anima ...
- Python3 迭代器,生成器,装饰器
1.迭代器 迭代器有两个基本方法,iter()和next(),next()完成后会引发StopIteration异常 a='abcdef' b=iter(a) #创建迭代器对象 print(type( ...
- day04 迭代器&生成器&装饰器
目录 1.迭代器 2.生成器 3.推导式 4.匿名函数 5.内置函数 6.递归 7.闭包 8.装饰器 一.迭代器 特点: 1. 省内存 2. 只能向前. 不能反复 3. 惰性机制 让不同的数据类型 ...
- Python(迭代器 生成器 装饰器 递归 斐波那契数列)
1.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大优 ...
- python学习笔记(5)--迭代器,生成器,装饰器,常用模块,序列化
生成器 在Python中,一边循环一边计算的机制,称为生成器:generator. 如: >>> g = (x * x for xin range(10)) >>> ...
- 4.python迭代器生成器装饰器
容器(container) 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中.通常这类数据结构把所有的元素存储在内存中 ...
随机推荐
- javascript之数组的6种去重方法
去重 var arr=[11,11,333,4,4,5,66,66,7]; // 方法一:在新数组内判断不存在时加入 var newarr1=[]; function quchong1(){ for( ...
- 哈希表的C实现(二)
上次大致分析了一下哈希表的链地址法的实现,今天来分析一下另一种解决哈希冲突的做法,即为每个Hash值,建立一个Hash桶(Bucket),桶的容量是固定的,也就是只能处理固定次数的冲突,如104857 ...
- HNOI2017 day1 T3 礼物
题目大意: 我的室友最近喜欢上了一个可爱的小女生.马上就要到她的生日了,他决定买一对情侣手环,一个留给自己,一个送给她.每个手环上各有 n 个装饰物,并且每个装饰物都有一定的亮度.但是在她生日的前一天 ...
- Laravel 5 微信小程序扩展
小程序官方的加解密 SDK 已经非常清楚了,只不过改成 Laravel 风格而已,仅仅相当于搬砖工.至于重复造轮子,我发现其他人的扩展解密用户信息的时候代码出错了,并且需要安装一个 Laravel 的 ...
- Appium+python自动化
名称 链接地址 Appium+python自动化8-Appium Python API(上) http://mp.weixin.qq.com/s/WvpT5oRrYY22avI95FuypQ Appi ...
- javascript 布尔类型
true和false 表达式为false的情况 1 false 2 NaN 3 0 4 字符串的空 " " 5 null 6 undefined
- bzoj4773
矩阵乘法 ...爆零了... 想到Floyd,却不知道怎么限制点数... 其实我们只要给Floyd加一维,dp[i][j][k]表示当前走过了i个点,从j到k的最短距离,然后这样可以倍增,最后看是否有 ...
- python学习笔记3-循环1
1 while break continue #while语句 ''' while 判断条件: 执行语句…… ''' count = 0 while (count < 9): print ('T ...
- 任务41:Individual authentication 模板
使用命令行创建项目 会自动加上ef core和Identity core代码的示例 默认创建mvc是不带Identity的 dotnet new -help:查看可用的命令: -au:Individu ...
- Codeforces - 474D - Flowers - 构造 - 简单dp
https://codeforces.com/problemset/problem/474/D 这道题挺好的,思路是这样. 我们要找一个01串,其中0的段要被划分为若干个连续k的0. 我们设想一个长度 ...