Python全栈开发之4、迭代器、生成器、装饰器
一、迭代器
1、为何要有迭代器?
对于序列类型:字符串、列表、元组,我们可以使用索引的方式迭代取出其包含的元素。但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器
2、什么是可迭代对象?
可迭代对象指的是内置有__iter__方法的对象,即obj.__iter__,如下
'hello'.__iter__ #字符串
(1,2,3).__iter__ #元组
[1,2,3].__iter__ #列表
{'a':1}.__iter__ #字典
{'a','b'}.__iter__ #集合
open('a.txt').__iter__ #文件
3、什么是迭代器?
可迭代对象执行obj.__iter__()得到的结果就是迭代器对象
而迭代器对象指的是即内置有__iter__又内置有__next__方法的对象
但是,list
、dict
、str
等可迭代对象并没有__next__()方法,所以它不是迭代器
可以把使用iter()
函数把list
、dict
、str
等可迭代对象变成迭代器
from collections import Iterator a=isinstance([],Iterator)
b=isinstance((),Iterator)
c=isinstance({},Iterator)
d=isinstance('abc',Iterator)
e=isinstance((i for i in range(10)),Iterator)
f=isinstance(100,Iterator)
print(a)
print(b)
print(c)
print(d)
print(e)
print(f) 输出:
False
False
False
False
True
False
使用isinstance()判断一个对象是否是可迭代对象
str1='hello' #字符串
tuple1=(1,2,3) #元组
list1=[1,2,3] #列表
dict1={'a':1} #字典
set1={'a','b'} #集合 #使用iter()方法把可迭代对象变成迭代器
iter_str=iter(str1)
iter_tuple=iter(tuple1)
iter_list=iter(list1)
iter_dict=iter(dict1)
iter_set=iter(set1) print(iter_str.__next__())
print(iter_tuple.__next__())
print(iter_list.__next__())
print(iter_dict.__next__())
print(iter_set.__next__())
把list、dict、str等可迭代对象变成迭代器
4、for循环
#基于for循环,我们可以完全不再依赖索引去取值了
dic={'a':1,'b':2,'c':3}
for k in dic:
print(dic[k]) #for循环的工作原理 #1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
#2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
#3: 重复过程2,直到捕捉到异常StopIteration,结束循环
5、迭代器的缺点
#优点:
- 提供一种统一的、不依赖于索引的迭代方式
- 惰性计算,节省内存
#缺点:
- 无法获取长度(只有在next完毕才知道到底有几个值)
- 一次性的,只能往后走,不能往前退
二、生成器
1、什么是生成器?
可以理解为一种数据类型、这种数据类型实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__()方法才可以),所以生成器就是可迭代对象。
2、生成器在Python中的表现形式
1、生成器函数
常规函数定义、但是是使用yield语句而不是使用return返回结果
yield语句一次返回一个结果、在每个结果中间挂起函数的状态 2、生成器表达式
类似于列表推导、但是生成器返回按需产生一个对象而不是一次构建一个结果列表
3、列表生成式
现在有一个需求,需要把列表[0,1,2,3,4,5,6,7,8,9]里的每个元素都加1,怎么实现?有以下几种方式:
list1=[0,1,2,3,4,5,6,7,8,9] for index,i in enumerate(list1):
list1[index]=i+1 print(list1) #原值修改 或者 a=[]
for i in range(10):
a.append(i*2)
print(a)
列表生成式写法
num_list = [ i*2 for i in range(10) ] #或者赋值
num_list = [ "数字%s"%i for i in range(10) ]
print(num_list) #输出:
['数字0', '数字1', '数字2', '数字3', '数字4', '数字5', '数字6', '数字7', '数字8', '数字9'] #结合三元表达式 num_list = [ "数字%s"%i for i in range(10) if i > 5] print(num_list)
#输出:
['数字6', '数字7', '数字8', '数字9']
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。
在Python中,这种一边循环一边计算的机制,称为生成器:generator。
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]
改成()
,就创建了一个生成器:
num_list = ("数字%s"%i for i in range(10) if i > 5) print(num_list.__next__())
print(num_list.__next__())
print(num_list.__next__()) #输出:
数字6
数字7
数字8
4、yield生成器函数
只要函数中存在yield,这个函数就是一个生成器函数
yield功能:1、相当于return一个返回值。2、保存函数的状态,以便下次从它离开的地方执行
def test(): yield 1
yield 2
yield 3
yield 4 num=test()
print(num.__next__())
print(num.__next__())
print(num.__next__())
print(num.__next__())
#输出:1
#
#
#
def fib(max):
n,a,b=0,0,1
while n<max:
# print(b)
yield b
a,b=b,a+b
n=n+1 gen=fib(10)
for i in gen:
print(i)
yield实现斐波拉契数列
import time
def consumer(name):
print("%s准备吃包子了"%name)
while True:
baozi=yield print('包子[%s]来了,被%s吃了'%(baozi,name)) # c1=consumer('lily')
# c1.__next__()
#
# c1.send('韭菜') def producer(name):
c=consumer('A')
c2=consumer('B')
c.__next__()
c2.__next__()
print('%s开始做包子了'%name)
for i in range(10):
time.sleep(1)
print('做了两个包子')
c.send(i)
c2.send(i) producer('Tom')
通过yield实现在单线程的实现并发运算
#yield相当于return控制的是函数的返回值
#x=yield的另外一个特性是,接收send()传过来的值赋值给yield def func():
print("yield来啦") name=yield print("yield接收send传参-%s"%name)
yield 2
print("下一步yield执行啦") test=func() print(test.__next__()) # 这一步打印的yield返回值是None res=test.send('Tom') #把Tom传给yield然后赋值给name,执行到yield 2返回 send相当于一次next操作 print(res)
yield-send()方法
三、装饰器
定义:装饰器本质上是一个函数
功能:就是为其他函数添加附加功能
原则:1.不能修改被装饰的函数的源代码
2.不能修改被装饰的函数的调用方式
#实现装饰器的知识: #1.函数即变量 #2.高阶函数:满足下面两个条件 #a: 把一个函数名当做实参传给另外一个函数 (在不修改被装饰函数源代码的情况下为其添加功能) #b: 返回值中包含函数名(不改变函数的调用方式) #3.嵌套函数 #高阶函数+嵌套函数+闭包 =装饰器
import time def timer(func):
def deco(*args,**kwargs):
start_time=time.time()
func(*args,**kwargs) #会往上一级找
end_time=time.time()
print('the func run time is %s'%(end_time-start_time))
return deco
@timer
def test1(name):
time.sleep(3)
print('in the test1')
print(name)
@timer
def test2():
time.sleep(3)
print('in the test2') #test1=timer(test1)
#test2=timer(test2) test1('sunhao')
test2()
装饰器例子
import time def timmer(func):
def wrapper():
start_time=time.time()
result=func() #拿到func函数的返回值
stop_time=time.time()
print('the func run time is %s'%(stop_time-start_time))
return result #再返回
return wrapper def test():
time.sleep(1)
print('in the test1') res=timmer(test) #返回的是wrapper的地址 timmer(test) 相当于@timmer res() #执行的是wrapper函数 #把timmer(test)赋值给test,再执行test(),就没修改被装饰的函数的调用方式
import time
def timmer(func):
def wrapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
return res
return wrapper @timmer #相当于foo=timmer(foo)
def foo():
time.sleep(3)
print('from foo') foo()
无参装饰器
user_list=[{'name':'allen','password':''},
{'name':'lucy','password':''},
{'name':'lily','password':''}
] current_user={'username':None,'login':False} def auth_type(func): def wrapper(*args,**kwargs): if current_user['username'] and current_user['login']: ret = func(*args,**kwargs)
return ret username=input("请输入用户名:").strip()
password=input("请输入密码:").strip()
for name in user_list: if name['name']== username and name['password'] == password:
current_user['username']=username
current_user['login']=True ret = func(*args, **kwargs)
return ret else:
print("用户名密码错误") return wrapper @auth_type
def index(name):
print("欢迎来%s购物商城"%name) @auth_type
def shopping(): print("shopping 吧") index('京东')
shopping()
登录认证模拟session
user_list=[{'name':'allen','password':''},
{'name':'lucy','password':''},
{'name':'lily','password':''}
] current_user={'username':None,'login':False} def outer(auth_type): def auth_func(func): def wrapper(*args,**kwargs):
print("认证类型是%s"%auth_type) if auth_type =="file":
if current_user['username'] and current_user['login']: ret = func(*args,**kwargs)
return ret username=input("请输入用户名:").strip()
password=input("请输入密码:").strip()
for name in user_list: if name['name']== username and name['password'] == password:
current_user['username']=username
current_user['login']=True ret = func(*args, **kwargs)
return ret else:
print("用户名密码错误") elif auth_type =='mysql': ret = func(*args, **kwargs)
return ret return wrapper return auth_func @outer(auth_type='file') #auth_func=outer(auth_type='filedb')
def index(name):
print("欢迎来%s购物商城"%name) @outer(auth_type='mysql')
def shopping(): print("shopping 吧") index('京东')
shopping()
有参装饰器
Python全栈开发之4、迭代器、生成器、装饰器的更多相关文章
- 战争热诚的python全栈开发之路
从学习python开始,一直是自己摸索,但是时间不等人啊,所以自己为了节省时间,决定报个班系统学习,下面整理的文章都是自己学习后,认为重要的需要弄懂的知识点,做出链接,一方面是为了自己找的话方便,一方 ...
- python全栈开发之路
一.Python基础 python简介 python数据类型(数字\字符串\列表) python数据类型(元组\字典) python数据类型(集合) python占位符%s,%d,%r,%f prin ...
- python全栈开发之OS模块的总结
OS模块 1. os.name() 获取当前的系统 2.os.getcwd #获取当前的工作目录 import os cwd=os.getcwd() # dir=os.listdi ...
- Python全栈开发之3、深浅拷贝、变量和函数、递归、函数式编程、内置函数
一.深浅拷贝 1.数字和字符串 对于 数字 和 字符串 而言,赋值.浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址. import copy # 定义变量 数字.字符串 # n1 = 123 n1 ...
- Python全栈开发之MySQL(二)------navicate和python操作MySQL
一:Navicate的安装 1.什么是navicate? Navicat是一套快速.可靠并价格相宜的数据库管理工具,专为简化数据库的管理及降低系统管理成本而设.它的设计符合数据库管理员.开发人员及中小 ...
- Python全栈开发之14、Javascript
一.简介 前面我们学习了html和css,但是我们写的网页不能动起来,如果我们需要网页出现各种效果,那么我们就要学习一门新的语言了,那就是JavaScript,JavaScript是世界上最流行的脚本 ...
- Python全栈开发之1、输入输出与流程控制
Python简介 python是吉多·范罗苏姆发明的一种面向对象的脚本语言,可能有些人不知道面向对象和脚本具体是什么意思,但是对于一个初学者来说,现在并不需要明白.大家都知道,当下全栈工程师的概念很火 ...
- Python全栈开发之8、装饰器详解
一文让你彻底明白Python装饰器原理,从此面试工作再也不怕了.转载请注明出处http://www.cnblogs.com/Wxtrkbc/p/5486253.html 一.装饰器 装饰器可以使函数执 ...
- Python全栈开发之7、面向对象编程进阶-类属性和方法、异常处理和反射
一.类的属性 1.@property属性 作用就是通过@property把一个方法变成一个静态属性 class Room: def __init__(self,name,length,width,he ...
随机推荐
- Educational Codeforces Round 33 (Rated for Div. 2) B题
B. Beautiful Divisors Recently Luba learned about a special kind of numbers that she calls beautiful ...
- Luogu P2324 [SCOI2005]骑士精神 搜索
刚开始写了个没迭代的...结果过了$qwq$ 然后迭个代..更快了.. #include<cstdio> #include<iostream> #define R regist ...
- css(name|pro|[,val|fn])
css(name|pro|[,val|fn]) 概述 访问匹配元素的样式属性.大理石平台支架 jQuery 1.8中,当你使用CSS属性在css()或animate()中,我们将根据浏览器自动加上前缀 ...
- sass,compass学习笔记总结
最近在进行百度前端技术学院的任务,知道自己基础薄弱,可没想到弱到这种地步,同时在安装各种软件的同时遇到了各种坑,查阅了各种资料,一个个解决的时候也发现自己凌乱了.学习总结,在脑海中形成自己的学习系统才 ...
- 5.使用Ribbon实现客户端侧负载均衡
Ribbon实现客户端侧负载均衡 5.1. Ribbon简介 Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法 ...
- mybatis 操作其他数据库的数据表
配置文件里面配置的数据库只是默认数据库,并不是只能操作默认数据库.(被自己蠢死了,唉) 1. 注解方式 使用BaseMapper方式操作数据表时,在表对应的实体类上的 @table 注解描述表名时加上 ...
- Windows环境安装MySQL8.0.11
网络开发数据库是必不可少的.曾经安装个Mysql,但是忘了.再次安装还是得百度.那还不如自己写篇博客记录一下呢,以后再忘记就看自己的博客好 Mysql官网安装地址(windows环境): https: ...
- R语言:各类型数据文件的导入
导入csv: read.csv() 导入txt: read.table() 注意,txt文件编码为unicode的导入r会报错,需转换成ANSI 读入excel:需要安装xlsx包,安装此包前先下载好 ...
- HearthBuddy炉石兄弟 如何调试ai
Sepefeets's update to botmaker's Silverfish AI This AI is a Custom Class for Hearthranger and Hearth ...
- Could not attach to a Hearthstone process.
配置的加载 // Hearthbuddy.Windows.ConfigurationWindow // Token: 0x060001DB RID: 475 RVA: 0x00088A3C File ...