迭代器、生成器、装饰器

在这个实验里我们学习迭代器、生成器、装饰器有关知识。

知识点

  • 迭代器
  • 生成器
  • 生成器表达式
  • 闭包
  • 装饰器

实验步骤

1. 迭代器

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

2. 生成器

在这一节我们学习有关 Python 生成器(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

3. 生成器表达式

在这一节我们学习生成器表达式(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 循环遍历所有行。

4. 闭包

闭包(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 是一个闭包,把一个给定的数字与预定义的一个数字相加。

5. 装饰器

装饰器(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

总结

本实验我们学习了迭代器和生成器以及装饰器这几个高级特性的定义方法和用法,也了解了怎样使用生成器表达式和怎样定义闭包。

python的迭代器、生成器、装饰器的更多相关文章

  1. Python基础-迭代器&生成器&装饰器

    本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 我现在有个需求,看 ...

  2. Python学习——迭代器&生成器&装饰器

    一.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素.迭代器仅 ...

  3. Python 迭代器&生成器,装饰器,递归,算法基础:二分查找、二维数组转换,正则表达式,作业:计算器开发

    本节大纲 迭代器&生成器 装饰器  基本装饰器 多参数装饰器 递归 算法基础:二分查找.二维数组转换 正则表达式 常用模块学习 作业:计算器开发 实现加减乘除及拓号优先级解析 用户输入 1 - ...

  4. 迭代器/生成器/装饰器 /Json & pickle 数据序列化

    本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 孩子,我现在有个需 ...

  5. Python之迭代器、装饰器、软件开发规范

    本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 孩子,我现在有个需 ...

  6. python学习笔记(5)--迭代器,生成器,装饰器,常用模块,序列化

    生成器 在Python中,一边循环一边计算的机制,称为生成器:generator. 如: >>> g = (x * x for xin range(10)) >>> ...

  7. 5.python(迭代器,装饰器,生成器,基本算法,正则)

    一,迭代器 1.迭代器  (1)迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,知道所有的元素被访问完结束.迭代器只能往前不会后退.  (2)对于原生支持随机访问的数据结构(如t ...

  8. 4.python迭代器生成器装饰器

    容器(container) 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中.通常这类数据结构把所有的元素存储在内存中 ...

  9. python中的迭代器&&生成器&&装饰器

    迭代器iterator 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束. 迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外, ...

  10. Python 全栈开发五 迭代器 生成器 装饰器

    一.迭代器 迭代协议:对象必须提供一个next方法,执行该方法后会返回迭代的下一项或者抛出Stopiteration异常,终止迭代.切只能往前,不能倒退. 可迭代对象:遵循迭代写一点对象就是可迭代对象 ...

随机推荐

  1. ES6常用知识点小结

    ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准. 因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015(简称ES2015).虽然浏览器在不 ...

  2. Struts2【OGNL、valueStack】就是这么简单

    什么是OGNL表达式? OGNL是Object Graphic Navigation Language 是操作对象属性的开源表达式. Struts2框架使用OGNL作为默认的表达式语言. 为什么我们学 ...

  3. Maven 搭建 SSM 项目 (oracle)

    简单谈一下maven搭建 ssm 项目 (使用数据库oracle,比 mysql 难,所以这里谈一下) 在创建maven 的web项目时,常常会缺了main/java , main/test 两个文件 ...

  4. POJ1741

    树分治,每次把每个点的deep取出,排序...尺取法... # include <stdio.h> # include <stdlib.h> # include <ios ...

  5. iOS开发——自定义转场动画

    首先是UIPresentationController,这个控制器给modal新的viewController提供了下一步的view和转场的管理,从一个viewController被modal出来到被 ...

  6. 如何将VMware虚拟机迁移到AWS

    在工作中,我们一直在努力将我们的一些VMware工作负载转移到AWS,并且我的任务是将几个VMware虚拟机迁移到AWS,作为暂时的概念验证. 在本文中,我将展示如何设置AWS连接器并使用AWS服务器 ...

  7. Cglib及其基本使用

    前言 最近一直在看Spring源码,其实我之前一直知道AOP的基本实现原理: 如果针对接口做代理默认使用的是JDK自带的Proxy+InvocationHandler 如果针对类做代理使用的是Cgli ...

  8. js中url跳转问题

    问题描述:列表中有不同的企业名字,每个企业名字都有一个不同的链接,用id做为参数区分.点击不同的名字,根据id的不同跳转到对应的详情页,设置连接如下: 1. url = http://localhos ...

  9. Web前端有价值的博客文章汇总

    一.HTML 二.CSS 1.深入理解position和z-index属性 :https://www.cnblogs.com/zhuzhenwei918/p/6112034.html 2.BFC(清除 ...

  10. 为eclipse安装subclipse(SVN插件)

    1.打开eclipse,点击菜单Help->Install New Software 2.进入安装窗体后,点击安装窗体的右侧的Add按钮,然后在弹出的窗体中输入名称:Subclipse 1.12 ...