博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python学习笔记四(迭代器、生成器、内置函数)
阅读量:4605 次
发布时间:2019-06-09

本文共 7446 字,大约阅读时间需要 24 分钟。

一、迭代器

  1.迭代器定义

   迭代是一个重复的过程,每次重复一次迭代,并且每次迭代的结果都是下一次迭代的初始值。

l = ["aaa","bbb","ccc"]count = 0while count< len(l):    #每次重复完成后count都是下一次的初始值    print(l[count])    count+=1

  需要迭代器的原因:对于序列类型str、list、tuple可以依赖索引迭代取值,对于dict、set、文件需要提供不依赖索引取值的方式。

  可迭代对象:具有内置__iter__方法的对象。字符串、列表、元组、字典、集合和文件均为可迭代对象。

  迭代器对象:可迭代对象执行obj.__iter__()方法后得到的结果为迭代器对象。迭代器对象内置有__iter__和__next__方法。文件对象为迭代器对象。

  总结

  1.可迭代对象不一定是迭代器对象。

  2.迭代器对象一定是可迭代对象。

  3.调用obj.__iter__()方法,可得到迭代器对象,若本身为迭代器对象,执行该方法得到的仍然是它本身。

  2.迭代器的使用

   可迭代对象调用obj.__iter__()方法得到迭代器对象后,可使用obj.__next__()迭代取值,迭代器对象可直接调用obj.__next__()取值。

  obj.__next__()等同于next(obj),取完值后调用__next__会抛出StopIteration异常。

#每次调用__next__方法取一次值,取完之后再调用该方法会抛出StopIteration异常l = ["aaa","bbb","ccc"]iter_list = l.__iter__()print(iter_list.__next__())  print(iter_list.__next__())print(iter_list.__next__())print(iter_list.__next__())

  使用try...except捕获异常

d = {"a":212,"b":111,"c":222}iter_dict = d.__iter__()while True:    try:        print(next(iter_dict)) #字典迭代取到的为key    except StopIteration:        break

  for循环原理

  for k in obj

  a)调用in后的obj__iter=obj.__iter__()得到一个迭代器对象。

  b)  执行k=obj_iter.__next__()将取到的值赋给k,然后执行循环体。

  c)重复过程2,直到捕获到StopInteration异常,结束循环。

  3.迭代器的优缺点

  优点:

    a) 提供一种统一的、不依赖索引的取值方式,为for循环的实现提供了依据。

    b) 迭代器同一时间在内存中只有一个值,更节省内存。

  缺点:

    a) 只能往后取值,为一次性的。

    b) next执行完之前,不能统计值得个数,无获取长度。

二、生成器

  1.生成器定义

  只要函数内部包含有yield关键字,那么执行func()的到的就是生成器,不会执行函数内部代码,并且生成器就是迭代器。

def func():    print("1111111111")    yield 1    print("2222222222")    yield 2    print("3333333333")    yield 3g = func()   #g为生成器,生成器就是迭代器print(next(g))   #func()开始执行到第一个yield,并且打印yield返回值print(next(g))   #func()执行到第二个yield,并且打印yield返回值print(next(g))

  yield的功能:

    a) yield提供了一种自定义迭代器的方法

    b) yield于return的区别:yield可以返回多次值,return只能返回一次值。函数暂停与再继续的状态有yield保存。

  模拟管道,实现tail -f access.log | grep "404"

1 #tail -f access.log|grep "404" 2 import time 3 def tail(filepath): 4     with open(filepath,'rb') as f: 5         f.seek(0,2) 6         while True: 7             line = f.readline() 8 if line: 9 yield line 10 else: 11 time.sleep(0.05) 12 13 def grep(lines,pattern): 14 for line in lines: #调用tail后得到生成器对象,可使用for来迭代其中每一行内容 15 line =line.decode('UTF-8') 16 if pattern in line: 17 yield line 18 19 res = grep(tail("access.log"),"404") #res也为生成器对象,可使用for来迭代取值 20 for line in res: 21 print(line)
View Code

   2.协程函数

  表达式形式的yield,在使用时,第一次必须穿None,g.send(None)等同于next(g)

1 def eater(name): 2     print("%s开始吃了"%name) 3     food_list = [] 4     while True: 5         food = yield food_list 6         print("%s吃了%s"%(name,food)) 7  food_list.append(food) 8 9 g = eater("xxx") #创建生成器g 10 res1 = g.send(None) #初始化yield,拿到返回的空列表 11 print(res1) 12 res2 = g.send("米饭") #发送"米饭"给yield,继续执行代码到下一个yield,返回列表给res2 13 print(res1) 14 g.close() #结束迭代 15 res3 = g.send("面条") #无法发送和获取值 16 print(res3)
View Code

  实现功能:grep -rl 'python' /etc 

1 #从某个路径下搜索所有包含某个字符串的文件的路径 2 import os 3  4 def init(func): 5     def inner(*args,**kwargs): 6         res = func(*args,**kwargs) 7         next(res) 8         return res 9 return inner 10 11 #列出某个路径下所有文件的绝对路径 12 @init 13 def list_path(target): 14 while True: 15 file_path = yield 16 g = os.walk(file_path) 17 for pardir,_,files in g: 18 for file in files: 19 abs_path = "%s\%s"%(pardir,file) 20  target.send(abs_path) 21 22 #打开某个文件 23 @init 24 def openner(target): 25 while True: 26 abs_path = yield 27 with open(abs_path,"rb") as f: 28  target.send((abs_path,f)) 29 30 #读取文件中每一行 31 @init 32 def read_line(target): 33 while True: 34 abs_path,f = yield 35 for line in f: 36 flag = target.send((abs_path,line)) 37 if flag: 38 break 39 40 #从一行中查找某个字符 41 @init 42 def find_str(target,pattern): 43 flag = False #用于判断某个文件是否包含有重复的某个字符 44 pattern = pattern.encode("utf-8") 45 while True: 46 abs_path,line = yield flag 47 if pattern in line: 48  target.send(abs_path) 49 flag = True 50 51 #将结果打印出来 52 @init 53 def print_path(): 54 while True: 55 abs_path = yield 56 print(abs_path) 57 58 g = list_path(openner(read_line(find_str(print_path(),"abcdef")))) 59 g.send(r"D:\PycharmProjects")
View Code

  3.yield总结

  a) 可以把函数做成迭代器

  b) 对比return,可以返回多次值,可以挂起/保存函数的运行状态

三、面向过程编程

  面向过程是一种思路和思想,不依赖于具体的语言或语法,核心思想是过程二字,即按照流水线式分步骤解决问题。

  优点是复杂问题流程化,分解为简单的小功能。

  缺点是可扩展性差,修改流水线任一阶段,会影响到其他阶段。

  适合扩展性要求不高的场景,入linux内核、git、httpd等。

四、三元表达式、列表推导式、生成器表达式

  1.三元表达式

name = input(">>:").strip()res = "SB" if name=="xxx" else "NB"  #满足if条件,则返回if前的值,不满足则返回else后的值print(res)

  2、列表推导式

l = [str(i)+"xxx" for i in range(1,10)]     #为1-10所有数字添加后缀print(l)l = [str(i)+"xxx" for i in range(1,20) if i%2==0]  #1-20所有偶数加后缀print(l)

  3、生成器表达式

  将列表推导式的[]换为()就是生成器表达式。

#生成老母鸡,需要使用时调用next下蛋>>> chicken = ("鸡蛋%s"%i for i in range(1,10))>>> chicken
at 0x000001AFD64CDF68>>>> next(chicken)'鸡蛋1'>>> list(chicken) #第一个鸡蛋已经下过了,chicken可迭代,因此可转为列表['鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']

  4、声明式编程

   a) 将l=['xxx','abc_sb','aaa','bbb']中的字母全部变大写

l=['xxx','abc_sb','aaa','bbb']l = [i.upper()for i in l]print(l)

  b) 将l=['xxx','abc_sb','aaa','bbb']中以sb结尾的名字过滤掉,然后保存剩下的名字长度

l=['xxx','abc_sb','aaa','bbb']l = [len(i) for i in l if not i.endswith("sb")]print(l)

  c) 求文件test.txt中最长的行的长度(长度按字符个数算,需要使用max函数)

with open("test.txt",'r',encoding="utf-8") as f:    res = max(len(line) for line in f)    print(res)

  d) 求文件test.txt中总共包含的字符个数?思考为何在第一次之后的n次sum求和得到的结果为0?(需要使用sum函数)

with open("test.txt",'r',encoding="utf-8") as f:    res = sum(len(line) for line in f)    print(res)

  生成器只能往后取值,已经取完一次值后,再对生成器做求和结果为0

五、递归和二分法

  1.递归调用定义

  在调用一个函数的过程中,直接或间接调用了该函数本身,称之为递归调用。

  递归调用分为两个阶段:递推和回溯。

  python中使用sys.gettrcursionlimit()查看可递归调用的层数。

import sysprint(sys.getrecursionlimit())  #默认支持1000层递归调用l=[1,[2,[3,[4,[5,[6,[7,]]]]]]]def func(l):    for item in l:        if type(item) is list: func(item) else: print(item) func(l)

  2.python中递归调用特点

  python中递归调用效率低,需要在进入下一次递归时保留当前状态。其他语言中有尾递归优化,python中没有,并且对层级做了限制。

  递归使用的要求:

  a) 必须有一个明确的结束条件

  b)  每次进入更深一层递归时,问题规模比上一次有所减少

  c) 递归效率不高,层数过多易导致栈溢出

  3.二分法

1 l = [2,3,5,6,8,12,15,16,19,22,35,45,56,62,98,122,321] 2 def binary_search(l,num): 3     print(l) 4     mid_index = len(l)//2 5     if len(l) != 0: 6         if num < l[mid_index]: 7             binary_search(l[0:mid_index-1],num) 8 elif num > l[mid_index]: 9 binary_search(l[mid_index+1:],num) 10 else: 11 print("find it") 12 else: 13 print("can't find %s" % num) 14 binary_search(l,321)
二分法

六、匿名函数

  匿名函数一次性使用,随时随需定义,可应用在max、min、sorted、map、reduce、filter等函数中。

#找出薪水最高的人salaries = {    'abc':3222,    'def':111,    'aaa':431,    'xxx':4133}#普通方法g = zip(salaries.values(),salaries.keys())   #g为迭代器print(max(g))                  #max按照每次取值的第一个数来比较#定义函数的方法,打印出薪水最高的人的名字def func(k): return salaries[k] print(max(salaries,key=func)) #排序是按照key来排序,结果展示按照salaries默认结果展示 #使用匿名函数 print(max(salaries,key=lambda k:salaries[k]))

七、内置函数

  sorted

#薪水排序,输出人名salaries = {    'abc':3222,    'def':111,    'aaa':431,    'xxx':4133}print(sorted(salaries,key=lambda k:salaries[k])) print(sorted(salaries,key=lambda k:salaries[k],reverse=True))

  map

#给列表中所有元素批量添加后缀#普通方法names = ['xxx','aaa','eee']l =[]for name in names:    res = "%s_SB"%name    l.append(res)print(l)#使用map添加g = map(lambda name:'%s_SB'%name,names) print(g) #g为迭代器 print(list(g))

  filter

#筛选出某个序列中特定元素names = ["xxx_sb","aaa_sb","sss","ee_sb"]g = filter(lambda i:i.endswith("sb"),names)print(g)print(list(g))

  reduce

#筛选出某个序列中特定元素#某个序列中连续两个元素进行处理from functools import reduceprint(reduce(lambda x,y:x+y,range(1,101),100))   #最后的100为初始值,可以不添加。

 

转载于:https://www.cnblogs.com/n1ghtwatcher/p/8271116.html

你可能感兴趣的文章
nyist oj 138 找球号(二)(hash 表+位运算)
查看>>
Movidius软件手册阅读 2017-09-04
查看>>
ytu 1910:字符统计(水题)
查看>>
201671030110 姜佳宇 实验三作业互评与改进
查看>>
mysql-5.6.15 开启二进制文件
查看>>
python的沙盒环境--virtualenv
查看>>
软件自动化测试——入门、进阶与实战
查看>>
BZOJ1878 [SDOI2009]HH的项链 树状数组 或 莫队
查看>>
BZOJ3675 [Apio2014]序列分割 动态规划 斜率优化
查看>>
Django extend(继承)模板标签
查看>>
2016.10.24 继续学习
查看>>
产品功能对标 - 服务授权管理
查看>>
各地IT薪资待遇讨论
查看>>
splay入门
查看>>
带CookieContainer进行post
查看>>
C语言学习笔记--字符串
查看>>
CSS-上下文选择器
查看>>
ionic repeat 重复最后一个时要执行某个函数
查看>>
1.初识代码审计-基础
查看>>
APC注入
查看>>