Python编程技巧:第四章 - 生成器和迭代器深入解析

更新:11-15 民间故事 我要投稿 纠错 投诉

大家好,今天来为大家分享Python编程技巧:第四章 - 生成器和迭代器深入解析的一些知识点,和的问题解析,大家要是都明白,那么可以忽略,如果不太清楚的话可以看看本篇文章,相信很大概率可以解决您的问题,接下来我们就一起来看看吧!

###########1

it=iter(lines) # it=lines.__iter__()

而True:

尝试:

下一个(它)

除了StopIteration:

打印“完成迭代”

休息

################2

ABC 类(对象):

def __iter__(self):

返回ABC2()

ABC2 类(对象):

数量=100

def下一个(自己):

self.num -=1

if self.num 0:

引发StopIteration()

返回self.num

对于ABC(): 中的i

在生成器中打印ifor xxx in xxx

运行生成器内部代码,将yield的值一一取出####for xxx in xxx明白

def abc(x):

打印123

产量x

for i in abc("hello world")

打印我

#abc("hello world") 内置__iter__, next, send, throw 方法

## 类的实现

ABC 类(对象):

def __iter__(self):

返回self.abc("你好世界")

def abc(自身, x):

打印123

产量x

对于ABC(): 中的i

打印我

#与以下内容相同

项目=iter(ABC())

而True:

尝试:

打印items.next()

除了StopIteration:

break

迭代器

python中实现__iter__方法的对象是可以迭代的,即可以调用内置函数iter()方法并返回该对象。实现next()方法的对象实现了实际的迭代器,并获取iter()返回值的对象,不断调用next()方法class Fib(object):

def __init__(self):

自身.a, 自身.b=0, 1

def __iter__(self):

返回自我

def下一个(自己):

self.a, self.b=self.b, self.a + self.b

如果是self.a 100:

引发StopIteration()

返回self.a

fetch=iter(Fib()) #获取用于迭代的对象

而True:

#不断调用next(),捕获StopIteration并结束循环

尝试:

我=fetch.next()

打印我

除了StopIteration:

休息

#相当于XXX 中的xxx

对于Fib(): 中的i

print i

生成器

生成器是一个对象。堆栈帧的上下文被保留。

def abc(x):

打印123

产量x

abc("hello world") # 此时不会打印123。这一步将生成一个生成器对象。

abc("hello world").next() #此时执行生成器中的代码

4.4 实现深度优先的遍历树形节点的生成器

理解for循环的yield和其他对象的yieldclass Node(object):

def __init__(自身,值):

self._value=值

self._children=[]

def __repr__(self):

返回"Node{!r}".format(self._value)

def __iter__(self):

返回iter(self._children)

def add_child(自身,节点):

返回self._children.append(节点)

def 深度优先(自身):

"""

收益率与回报不同。再次调用时,会从原来的地方执行。

其他对象yield后,再次yield,分为两次

"""

屈服自我

对于self: 中的c

#下面的代码相当于yield from c.depth_first()

对于c.depth_first(): 中的项目

产量项目

如果__name__=="__main__":

根=节点(0)

子节点1=节点(1)

child2=节点(2)

子节点11=节点(11)

子节点21=节点(21)

root.add_child(child1)

root.add_child(child2)

child1.add_child(child11)

child2.add_child(child21)

child11.add_child(节点(100))

child21.add_child(节点(200))

child21.add_child(节点(201))

"""

了解for 循环:

ch 是形参,接受root.depth_first()返回的实参(相当于return)

root.depth_first() 必须实现迭代协议并且可以是生成器

"""

对于root.depth_first(): 中的ch

print chdepth_first()方法首先返回(yield)本身,并迭代每个节点的深度_first()方法,返回(yield)对应的元素。

传统方法的实现缺点是比较繁琐class Node2(object):

def __init__(自身,值):

self._value=值

self._children=[]

def __repr__(self):

返回"Node{!r}".format(self._value)

def __iter__(self):

返回iter(self._children)

def add_child(自身,节点):

返回self._children.append(节点)

def 深度优先(自身):

返回深度第一迭代器(自身)

类DepthFirstIterator(对象):

def __init__(self, start_node):

self._node=起始节点

self._children_iter=无

self._child_iter=无

def __iter__(self):

返回自我

def __next__(self):

如果self._children_iter 为None:

self._children_iter=iter(self._node)

返回self._node

elif self._child_iter:

尝试:

nextchild=next(self._child_iter)

返回下一个孩子

除了StopIteration:

self._child_iter=无

返回下一个(自身)

否则:

self._child_iter=next(self._children_iter).深度_first()

return next(self)

4.5 反向迭代

使用内置函数reverse()必须实现内置reversed()方法class Countdown(object) :

def __init__(自身,开始):

self.start=开始

def __iter__(self):

n=自启动

而n 0:

产量n

n -=1

def __reversed__(self):

n=1

而n=self.start:

产量n

n+=1

如果__name__=="__main__":

对于rr 反转(倒计时(30)):

打印

对于rr 倒计时(30):

从集合导入双端队列打印rr

4.6 带有外部参数生成器函数

类LineHistory:

def __init__(self,lines,hislen=3):

self.lines=线

self.history=deque(maxlen=hislen)

def __iter__(self):

对于lineno,枚举中的行(self.lines,1):

self.history.append((lineno, line))

屈服线

def 清除(自身):

self.history.clear()

4.7 迭代器切片

获取迭代器生成的切片对象

导入迭代工具

定义计数(n):

而True:

产量n

n+=1

c=计数(0)

# c[10:20] TypeError: "generator" 对象没有属性"__getitem__"

对于itertools.islice(c, 10, 21): 中的项目

打印项函数islice() 返回一个可以生成指定元素的迭代器,该迭代器会迭代

遍历并丢弃直到切片起始索引的所有元素。然后开始一一返回元素,直到切片的结束索引位置。缺点:迭代器中的数据不能重复使用。

4.8 跳过不需要的迭代部分

?跳过可迭代对象的开头而不影响其余对象?

创建一个迭代器,

只要函数predicate(item) 为True,iterable 中的项目就会被丢弃。

如果谓词返回False,则生成可迭代中的项目和所有后续项目。

从itertools 导入dropwhile

使用open("manage.py") 作为f:

for line in dropwhile(lambda line: line.startwith("#"), f):

打印行

4.9 排列组合实现

例如,排列A23,组合C23等。

从itertools 导入排列、组合、combinations_with_replacement

项目=["a", "b", "c"]

for c in permutations(items) # 排列A33

for c in permutations(items, 2) # 排列A33

for c in Combinations(items, 3) # 组合C23

for c in Combinations_with_replacement(items, 3) # 重用同一个元素3*3*3

4.10 序列上索引迭代

my_list=["a", "b", "c"]

对于idx,枚举中的val(my_list, 1):

当您想在迭代文件: 时使用错误消息中的行号时, print(idx, val) 的这种情况非常有用

def parse_data(文件名):

打开(文件名,"rt")作为f:

对于lineno,枚举中的行(f,1):

字段=line.split()

尝试:

计数=int(字段[1])

.

除了ValueError 为e:

print("行{}: 解析错误: {}".format(lineno, e))data=[ (1, 2), (3, 4), (5, 6), (7, 8) ]

对于n, (x, y) in enumerate(data)

4.11 迭代多个序列 zip()

zip() 将创建一个迭代器作为结果返回

基本用法压缩a=[1, 2, 3]

b=["w", "x", "y", "z"]

对于我在zip(a,b):

打印(一)

(1,"w")

(2,"x")

(3,"y")

从itertools 导入zip_longest

对于我在zip_longest(a,b,fillvalue=None):

打印(一)

(1, "w")

(2, "x")

(3,"y")

(None, "z") 将字典打包到列表headers=["name", "shares", "price"]

值=["ACME", 100, 490.1]

s=dict(zip(标题、值))

list(zip(headers, value))zip() 可以接受来自itertools 导入链的两个以上序列参数zip(a, b, c)

4.12 不同集合上元素的迭代 chain()

a=[1, 2, 3, 4]

b=["x", "y", "z"]

对于链中的x(a, b):

print(x)a, b 可以是不同类型的链(set、list)甚至链(dict、list)

#低效

对于a + b: 中的x

更好的

for x in chain(a, b): 第一种方案中,a + b操作会创建一个新的序列,并且要求a和b的类型一致

chian()没有这一步,所以如果输入序列很大的话会节省内存。当可迭代时

当对象类型不同时,chain() 也可以很好地工作。

4.13 创建数据管道

os.walk从文件夹中的某个位置开始遍历

# x为当前目录,y为当前目录包含的文件夹,z为当前目录中的文件

对于x、y、z,在os.walk(r"D:Workspacesell"):

用于z : 中的z 件

print "{}{}".format(x,zpieces)fnmatch.filter(filellist, filepat)

如果filelist是list,则返回与filepart匹配的文件。

如果filelist是str,则返回一个布尔值

#encoding:utf-8

导入操作系统

导入fnmatch

导入gzip

导入bz2

进口重新

def gen_find(filepat, 顶部):

"""

根据filepat的文件类型查找当前目录下的文件

"""

对于os.walk(top): 中的路径、目录列表、文件列表

# 过滤符合格式的地址并返回

对于fnmatch.filter 中的名称(filelist,filepat):

yield os.path.join(path, name) # 文件绝对地址的生成器

def gen_opener(文件名):

"""

打开文件、产生文件并关闭

"""

for filename in filenames: # 从生成器中获取绝对地址filename 是地址filename 是包含地址的生成器

如果文件名.endswith(".gz"):

f=gzip.open(文件名, "rt")

elif 文件名.endswith(".bz2"):

f=bz2.open(文件名,"rt")

##todo 可能有问题

否则:

f=打开(文件名,"r")

Yield f #文件对象生成器

f.close()

def gen_concatenate(迭代器):

for it in iterators: #it是一个文件对象,iterators是一个文件对象生成器

for items in it: # items 语句it 文件对象

yield items # 抛出句子生成器并使用for xx in xx 来外部获取

def gen_grep(模式,线条):

"""

匹配文本中的句子

"""

pat=重新编译(模式)

用于行中行:

如果帕特.搜索(行):

屈服线

lognames=gen_find("*.py", r"D:Workspacesell")

文件=gen_opener(日志名)

行=gen_concatenate(文件)

pylines=gen_grep(r"^class ",lines) #打印类名

对于pylines: 中的行

打印行

#todo我不太明白

#bytecolumn=(line.rsplit(None,1)[1] for line in pylines)

#bytes=(int(x) for x in bytecolumn if x !="-")

#print("Total", sum(bytes)) 无法理解嵌套生成器,请参见下面的示例

def gen1 ():

对于我在[[1,2,3,4,5],[6,7,8,9,0]]:

产量我

def gen2 (i):

对于i: 中的j

对于j: 中的k

产量k

g1=gen1()

g2=gen2(g1)

对于g2: 中的x

打印

4.14 递归生成器展开嵌套的序列

原代码使用yield from实现python2,不支持available for i in xx:yield i改为

#encoding:utf-8

从集合导入可迭代

def flatten(items,ignore_types=(str, bytes)):

对于items: 中的x

#isinstance(x, Iterable) 判断是否可迭代,如果是则继续递归

#not isinstance(x,ignore_types),排除字符串和字节,两者也可以迭代

如果isinstance(x, Iterable) 而不是isinstance(x,ignore_types):

对于我在展平(x):

产量我

否则:

产量x

项目1=[1, 2, [3, 4, [5, 6], 7], 8]

items2=["戴夫","保拉",["托马斯","刘易斯"]]

l1=[x for x in flatten(items1)]

l2=[x for x in flatten(items2)]

4.15 有序对象合并再排序

heapq.merge()

heapq.merge 生成器的迭代性质意味着它不会一次读取所有序列。这意味着您可以

在长序列中使用它,无需太多开销

导入堆

a=[1, 4, 7, 10]

b=[2, 5, 6, 11]

l=[x for x in heapq.merge(a, b)] ##heapq.merge(a, b) 是生成器

[1,2,4,5,6,7,10,11]

4.16 迭代器代替while循环

其实就是用遍历代替while。

路径:iter(functiong, status)可以迭代,具体请参考本节末尾

常用IO程序、伪代码

块大小=8192

def 读卡器:

而True:

数据=s.recv(CHUNKSIZE)

如果数据==b"":

休息

处理数据(数据)

f=open("views.py", "r")

读者(女)

#替换为iter()循环

def reader2(s):

for chunk in iter(lambda : s.recv(CHUNKSIZE),b""):

经过

#process_data(数据) 示例代码

导入系统

f=open("views.py","r")

for chunk in iter(lambda: f.read(10), ""):

n=sys.stdout.write(chunk)iter() 内置函数:

使用单参数Iter(func)时,fun对象支持迭代协议,否则会报错。

这两个参数是Iter(func, arg),它接受一个可选的可调用对象和一个标签(结果

tail) value作为输入参数,连续调用next(),当func的返回值与mark相同时,抛出StopIteration。

x=0

def func():

全局x

x+=1

打印x

返回x

而True:

我=迭代器(函数,100)

尝试:

i.next() #当返回值为100时抛出StopIteration

除了StopIteration:

用户评论

夜晟洛

Python Cookbook 的第四章果然很实用,学习生成器和迭代器能让我写出更简洁高效的代码。

    有17位网友表示赞同!

秒淘你心窝

我一直觉得 Python 是个很棒的语言,而这章详细讲解了高效内存管理的关键概念,我一定要好好消化一下。

    有7位网友表示赞同!

冷青裳

之前没太理解生成器和迭代器的区别,看了第四章豁然开朗,原来原理真的很巧妙!

    有9位网友表示赞同!

执笔画眉

最近在做数据处理的任务,学习一下 Python Cookbook 的第四章应该能帮我提高效率不少.

    有18位网友表示赞同!

╯念抹浅笑

书里的例子都写得很有逻辑,很容易理解生成器和迭代器的应用场景。

    有20位网友表示赞同!

孤自凉丶

想写出一些高效的算法,这本书绝对是宝典!第四章讲解的知识点确实非常实用。

    有13位网友表示赞同!

不要冷战i

终于明白为什么现在很多框架使用生成器了,这个设计模式太牛了!

    有8位网友表示赞同!

屌国女农

以前用循环实现的功能,可以用生成器来写得更简洁美观,学习新知识永远没有迟来的理由。

    有11位网友表示赞同!

ok绷遮不住我颓废的伤あ

Python Cookbook 的第四章简直是我的菜!对提高编程效率很有帮助。

    有15位网友表示赞同!

久爱不厌

准备好好复习下 Python 生成器和迭代器,相信这会让我在接下来的项目中大放异彩!

    有12位网友表示赞同!

我的黑色迷你裙

感觉学习生成器和迭代器后,可以写出更优美、更轻量的代码了,期待早点应用到实际项目中。

    有14位网友表示赞同!

像从了良

Python Cookbook 的第四章讲解的很深入,不仅介绍了理论知识,还提供了很多实践案例。

    有14位网友表示赞同!

疲倦了

现在越来越觉得学习生成器和迭代器的重要性,它真是一项提升编程能力的宝贵技能!

    有7位网友表示赞同!

走过海棠暮

我正在学习 Python,Python Cookbook 真是个好资源,特别是第四章对生成器和迭代器进行了很好的介绍。

    有18位网友表示赞同!

窒息

终于找到了理解这两种概念的方法,感谢 Python Cookbook 的作者!

    有18位网友表示赞同!

無極卍盜

用生成器处理大量数据可以节省内存空间,这是一个很实用的特性。

    有12位网友表示赞同!

あ浅浅の嘚僾

Python Cookbook 总是那么实用,第四章的讲解让我对生成器和迭代器的应用有更深刻的理解。

    有18位网友表示赞同!

心贝

我开始尝试用生成器来写一些代码,感觉确实比传统的循环方式更加简洁高效!

    有5位网友表示赞同!

失心疯i

学习 Python 的同学一定要仔细阅读 Python Cookbook 第四章,它会让你在编程中更上一层楼!

    有5位网友表示赞同!

【Python编程技巧:第四章 - 生成器和迭代器深入解析】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活

上一篇:探索人际精神沟通的重要性 下一篇:《盛夏情愫》(第四十四章)