python迭代器、装饰器和生成器
装饰器
1、装饰器的作用
1. 装饰器作用:本质是函数(装饰其他函数)就是为其他函数添加其他功能
2. 装饰器必须准寻得原则:
1)不能修改被装饰函数的源代码
2)不能修改被装饰函数的调用方式
3.实现装饰器知识储备:
1)函数即“变量”
2)高阶函数
3)嵌套函数 高阶函数+潜逃函数=》装饰器
2、使用高阶函数模仿装饰器功能
1)定义:把一个函数名当做实参传给另一个函数
2)返回值中包含函数名
3)下面使用高阶函数虽然可以实现装饰器的一些功能,但是违反了装饰器不能改变调用方式的原则,
以前使用bar()现在将调用方式改编成了test1(bar)就是将bar的函数名当做变量传给了test1()
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import time def timer(func):
start_time = time.time()
func()
print '函数执行时间为', time.time() - start_time def test():
print '开始执行test'
time.sleep(3)
print 'test执行结束' timer(test)
'''
开始执行test
test执行结束
函数执行时间为 3.00332999229
''' 改变了调用方式
4)高阶函数——不修改高阶函数的调用方式增加新的功能(但是无法传参数)
注:bar = test2(bar) 等价于:@timer重新将函数名bar赋值,将原函数bar的内存地址当做实参传递该函数test2(),再将test2()赋值给bar
import time
def bar():
time.sleep(3)
print("in the bar")
def test2(func):
print(func)
return func
bar = test2(bar)
bar() 不改变调用方式
5)嵌套函数
嵌套函数:在一个函数中嵌套另一个函数,并在函数内部调用
def foo():
print("in the foo")
def bar():
print("in the bar")
bar()
foo() 嵌套函数
3、装饰器1----能够适应90%的业务需求
在装饰器中 @timer等价于 test1=timer(test1)
1. 在timer()函数中返回值是return deco
2. 所以timer(test1)作用是将函数test1内存地址当做参数传递给timer()
3. timer() 函数最后将运行后的函数deco内存地址作为返回值返回
4. test1=timer(test1)作用就是将将deco函数内存地址赋值给test1,所以最后运行test1()就相当于运行deco()
5. 所以最后调用时给test2()传入参数就相当于给deco传入参数
import time
def timer(func): #timer(test1) func=test1
def deco(*args,**kwargs):
start_time = time.time()
func(*args,**kwargs) #run test1
stop_time = time.time()
print("running time is %s"%(stop_time-start_time))
return deco
@timer # test1=timer(test1)
def test1():
time.sleep(3)
print("in the test1")
@timer
def test2(name):
print("in the test2",name)
test1()
test2("tom") 装饰器01
4、装饰器2----对特定网页进行身份验证
import time
user,passwd = 'aaa',''
def auth(func):
def wrapper(*args,**kwargs):
username = input("Username:").strip()
password = input("Password:").strip()
if user == username and password == passwd:
print("User has passed authentication")
res = func(*args,**kwargs) #这里执行func()相当于执行调用的函数如home()
return res #为了获得home()函数返回值,可以将执行结果赋值给res然后返回print(home())结果是"from home"而不是"None"了
else:
exit("Invalid username or password")
return wrapper
def index():
print("welcome to index page")
@auth
def home():
print("welcome to home page")
return "from home"
@auth
def bbs():
print("welcome to bbs page")
index()
print(home()) #在这里调用home()相当于调用wrapper()
bbs() 装饰器02
5、装饰器3----终极篇:实现对不同网页不同方式的身份认证
@auth(auth_type="local")代码作用
- 在上面的代码中使用@auth相当于先将home函数的内存地址当做变量传入auth()函数,执行结果后home()相当于wrapper()
- 而在这里验证的时候犹豫@auth(auth_type="local")中有()括号,那么就相当于将执行auth()函数而且是将auth_type="local当做参数传入到auth()函数执行
- 所以outer_wrapper函数也会执行,outer_wrapper函数的执行结果返回的就是wrapper()函数的内存地址
- 所以最终结果同样是执行home()函数就相当于执行wrapper函数
- 但是有所不同的是着这个版本中我们可以在外层的auth函数中传入新的参数帮组我们根据需求判断
import time
user,passwd = 'aaa',''
def auth(auth_type):
print("auth func:",auth_type)
def outer_wrapper(func):
def wrapper(*args, **kwargs):
print("wrapper func args:", *args, **kwargs)
if auth_type == "local":
username = input("Username:").strip()
password = input("Password:").strip()
if user == username and passwd == password:
print("\033[32;1mUser has passed authentication\033[0m")
res = func(*args, **kwargs) # from home
print("---after authenticaion ")
return res
else:
exit("\033[31;1mInvalid username or password\033[0m")
elif auth_type == "ldap":
print("搞毛线ldap,不会。。。。") return wrapper
return outer_wrapper def index():
print("welcome to index page")
@auth(auth_type="local") # home = wrapper()
def home():
print("welcome to home page")
return "from home" @auth(auth_type="ldap")
def bbs():
print("welcome to bbs page") index()
print(home()) #wrapper()
bbs() 装饰器03
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import time
def auth(auth_type):
print("auth func:",auth_type)
def outer_wrapper(func):
def wrapper(*args, **kwargs):
print("wrapper func args:", *args, **kwargs)
print('运行前')
func(*args, **kwargs)
print('运行后')
return wrapper
return outer_wrapper @auth(auth_type="local") # home = wrapper()
def home():
print("welcome to home page")
return "from home"
home() 三级装饰器简写
6、使用闭包实现装饰器功能
1)闭包概念
1. 在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用,这样就构成了一个闭包
2. 一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。
3. 但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import time def timer(func): #timer(test1) func=test1
def deco(*args,**kwargs): # # 函数嵌套
start_time = time.time()
func(*args,**kwargs) # 跨域访问,引用了外部变量func (func实质是函数内存地址)
stop_time = time.time()
print "running time is %s"%(stop_time-start_time)
return deco # 内层函数作为外层函数返回值 def test(name):
print "in the test2",name
time.sleep(2) test = timer(test) # 等价于 ==》 @timer语法糖
test("tom")
'''
运行结果:
in the test2 tom
running time is 2.00302696228
''' 闭包实现装饰器功能
生成器
定义:
1、生成器,即生成一个容器。
2、在Python中,一边循环,一边计算的机制,称为生成器。
3、生成器可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他数据类型需要调用自己的内置iter()方法或__iter__()的内置函数),
所以,生成器就是一个可迭代对象。
1、生成器的作用
1. 通过列表生成式,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限的。
2. 而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
3. 所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?
4. 这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
5. 要创建一个generator,有很多种方法,第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
print( [i*2 for i in range(10)] ) #列表生成式: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
print( (i*2 for i in range(10)) ) #生 成 器: <generator object <genexpr> at 0x005A3690>
6. 我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?
7. 如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:
g = (i*2 for i in range(10))
print( g.__next__() ) # 0
print( g.__next__() ) # 2
2、生成器工作原理
1)生成器是这样一个函数,它记住上一次返回时在函数体中的位置。
2)对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的所有局部变量都保持不变。
3)生成器不仅“记住”了它数据状态;生成器还“记住”了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置。
4)生成器是一个函数,而且函数的参数都会保留。
5)迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的
3、yield生成器运行机制
1)在Python中,yield就是这样的一个生成器。
2)当你问生成器要一个数时,生成器会执行,直至出现 yield 语句,生成器把yield 的参数给你,之后生成器就不会往下继续运行。
3)当你问他要下一个数时,他会从上次的状态开始运行,直至出现yield语句,把参数给你,之后停下。如此反复
4)在python中,当你定义一个函数,使用了yield关键字时,这个函数就是一个生成器
5)它的执行会和其他普通的函数有很多不同,函数返回的是一个对象,而不是你平常所用return语句那样,能得到结果值。如果想取得值,那得调用next()函数
6)每当调用一次迭代器的next函数,生成器函数运行到yield之处,返回yield后面的值且在这个地方暂停,所有的状态都会被保持住,直到下次next函数被调用,或者碰到异常循环退出。
def fib(max_num):
a,b = 1,1
while a < max_num:
yield b
a,b=b,a+b g = fib(10) #生成一个生成器:[1,2, 3, 5, 8, 13]
print(g.__next__()) #第一次调用返回:1
print(list(g)) #把剩下元素变成列表:[2, 3, 5, 8, 13] yield实现fib数
4、yield实现单线程下的并发效果
1、yield相当于 return 返回一个值,并且记住这个返回的位置,下次迭代时,代码从yield的下一条语句开始执行。
2、send() 和next()一样,都能让生成器继续往下走一步(下次遇到yield停),但send()能传一个值,这个值作为yield表达式整体的结果
def consumer(name):
print("%s 准备吃包子啦!" %name)
while True:
baozi = yield
print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
c = consumer("Tom")
c.__next__()
b1 = "韭菜馅包子"
c.send(b1) # c.send(b1)作用:
# c.send()的作用是给yied的传递一个值,并且每次调用c.send()的同时自动调用一次__next__
'''运行结果:
Tom 准备吃包子啦!
包子[韭菜馅包子]来了,被[Tom]吃了!
''' 一次调用
import time
def consumer(name):
print("%s 准备吃包子啦!" %name)
while True:
baozi = yield
print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
def producer(name):
c = consumer('A')
c2 = consumer('B')
c.__next__()
c2.__next__()
print("老子开始准备做包子啦!")
for i in range(10):
time.sleep(1)
print("做了2个包子!")
c.send(i)
c2.send(i)
producer("alex") '''运行结果:
A 准备吃包子啦!
B 准备吃包子啦!
老子开始准备做包子啦!
做了2个包子!
包子[0]来了,被[A]吃了!
包子[0]来了,被[B]吃了!
做了2个包子!
包子[1]来了,被[A]吃了!
包子[1]来了,被[B]吃了!
做了2个包子!
包子[2]来了,被[A]吃了!
包子[2]来了,被[B]吃了!
做了2个包子!
包子[3]来了,被[A]吃了!
包子[3]来了,被[B]吃了!
做了2个包子!
包子[4]来了,被[A]吃了!
包子[4]来了,被[B]吃了!
做了2个包子!
包子[5]来了,被[A]吃了!
包子[5]来了,被[B]吃了!
''' for循环调用
迭代器
定义:
迭代器是访问集合内元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素都被访问一遍后结束。
1、迭代器和可迭代对象
1. 凡是可作用于for
循环的对象都是可迭代的(Iterable)类型;
2. 凡是可作用于next()
函数的对象都是迭代器(Iterator)
类型,它们表示一个惰性计算的序列;
3. 集合数据类型如list
、dict
、str
等是可迭代的但不是迭代器,不过可以通过iter()
函数获得一个Iterator
对象。
4. Python的for
循环本质上就是通过不断调用next()
函数实现的
总结: 一个实现了__iter__方法的对象是可迭代的,一个实现next方法的对象是迭代器
2、迭代器的两个方法
1. 迭代器仅是一容器对象,它实现了迭代器协议。它有两个基本方法
㈠ next方法
返回容器的下一个元素
㈡ __iter__方法
返回迭代器自身
2. 迭代器是访问集合内元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素都被访问一遍后结束。
3. __iter__方法会返回一个迭代器(iterator),所谓的迭代器就是具有next方法的对象。
4. 在调用next方法时,迭代器会返回它的下一个值,如果next方法被调用,但迭代器中没有值可以返就会引发一个StopIteration异常
a = iter([1,2,]) #生成一个迭代器
print(a.__next__())
print(a.__next__())
print(a.__next__()) #在这一步会引发 “StopIteration” 的异常
3、判断是迭代器和可迭代对象
注:列表,元组,字典是可迭代的但不是迭代器
from collections import Iterable
print(isinstance([],Iterable)) #True
print(isinstance({},Iterable)) #True
print(isinstance((),Iterable)) #True
print(isinstance("aaa",Iterable)) #True
print(isinstance((x for x in range(10)),Iterable)) #True
4、列表不是迭代器,只有生成器是迭代器
from collections import Iterator
t = [1,2,3,4]
print(isinstance(t,Iterator)) #False
t1 = iter(t)
print(isinstance(t1,Iterator)) #True
5、自定义迭代器
#! /usr/bin/env python
# -*- coding: utf-8 -*-
class MyRange(object):
def __init__(self, n):
self.idx = 0
self.n = n def __iter__(self):
return self def next(self):
if self.idx < self.n:
val = self.idx
self.idx += 1
return self.n[val]
else:
raise StopIteration() l = [4,5,6,7,8]
obj = MyRange(l)
print obj.next() #
print obj.next() #
print obj.next() # 自定义迭代器
6、迭代器与生成器
#! /usr/bin/env python
# -*- coding: utf-8 -*
l = [1,2,3,4,5] # 列表是一个可迭代对象,不是一个迭代器
print dir(l) # 所以 l 中有 __iter__() 方法,没有 __next__()方法
iter_obj = l.__iter__() # __iter__()方法返回迭代器对象本身(这个迭代器对象就会有 next 方法了) print '###################################\n'
print iter_obj.next() #
print iter_obj.next() #
print iter_obj.next() #
python迭代器、装饰器和生成器的更多相关文章
- Python之路-python(装饰器、生成器、迭代器、Json & pickle 数据序列化、软件目录结构规范)
装饰器: 首先来认识一下python函数, 定义:本质是函数(功能是装饰其它函数),为其它函数添加附件功能 原则: 1.不能修改被装饰的函数的源代码. 2.不 ...
- python基础-装饰器,生成器和迭代器
学习内容 1.装饰器 2.生成器 3.迭代器 4.软件目录结构规范 一:装饰器(decorator) 1.装饰器定义:本质就是函数,用来装饰其他函数,即为其他函数添加附加功能. 2.装饰器原则:1)不 ...
- python之装饰器、生成器、内置函数、JSON
一.装饰器: 装饰器,器在这里的意思是函数,也就是装饰函数.作用是给其他函数添加新功能,它可以不改变原有的函数,原来的函数和原来一模一样,什么都不需要改变,只需要在函数外部加上调用哪个装饰器就可以了, ...
- Python学习---装饰器/迭代器/生成器的学习【all】
Python学习---装饰器的学习1210 Python学习---生成器的学习1210 Python学习---迭代器学习1210
- Python之装饰器、迭代器和生成器
在学习python的时候,三大“名器”对没有其他语言编程经验的人来说,应该算是一个小难点,本次博客就博主自己对装饰器.迭代器和生成器理解进行解释. 为什么要使用装饰器 什么是装饰器?“装饰”从字面意思 ...
- Python装饰器、生成器、内置函数、json
这周学习了装饰器和生成器,写下博客,记录一下装饰器和生成器相关的内容. 一.装饰器 装饰器,这个器就是函数的意思,连起来,就是装饰函数,装饰器本身也是一个函数,它的作用是用来给其他函数添加新功能,比如 ...
- 我终于弄懂了Python的装饰器(一)
此系列文档: 1. 我终于弄懂了Python的装饰器(一) 2. 我终于弄懂了Python的装饰器(二) 3. 我终于弄懂了Python的装饰器(三) 4. 我终于弄懂了Python的装饰器(四) 一 ...
- Python各式装饰器
Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义. 一.函数式装饰器:装饰器本身是一个函数. 1.装饰函数:被装饰对象是一个函数 [1]装饰器无参数: a.被装饰对象无参数: ...
- Python札记 -- 装饰器补充
本随笔是对Python札记 -- 装饰器的一些补充. 使用装饰器的时候,被装饰函数的一些属性会丢失,比如如下代码: #!/usr/bin/env python def deco(func): def ...
随机推荐
- windows 下 基于express搭建 https协议的网站
参考 https://blog.csdn.net/xingyanchao/article/details/79362443 问题在于生成SSL证书的时候Windows环境下会报错 解决方案 参考 ht ...
- [PyTorch入门]之迁移学习
迁移学习教程 来自这里. 在本教程中,你将学习如何使用迁移学习来训练你的网络.在cs231n notes你可以了解更多关于迁移学习的知识. 在实践中,很少有人从头开始训练整个卷积网络(使用随机初始化) ...
- Thinkpad E40热键不能使用解决办法
Thinkpad E40 0578M68笔记本电脑安装windows7 64bit和联想官网驱动后,键盘最上面一排热键中,除了静音.减小音量和增大音量之外,其余的热键均不可用,解决办法: 到联想官网下 ...
- jquery关于checkbox复选框是否被选中的问题
本人在项目中需要用到,判断哪些复选框被用户选中.自然而然想到用 if($('').attr('checked') == true) 但是不管有没有选,$('').attr('checked')返回的都 ...
- 关于RN的热更新
写点关于RN的热更新和RN版本升级后的强制更新.以及优化白屏问题 在APPDelegate中加载RN,一般的加载方式是:RCTRootView *rootView= [[RCTRootView all ...
- 代工黑马,纬创如何强吞iPhone?
现在,智能手机市场非常得意兴阑珊,以苹果为首的最强大脑似乎再也想不出什么好的创意,iPhone7也只不过是旧机种的翻新款式,看上去跟一块板砖.一块镜子差不多:软体方面则出现了大批的"过度 ...
- 你有哪些相见恨晚的Chrome 扩展?
「Chrome 没插件,香味少一半」,本期我们就来一起盘点一下chrome上那些相见恨晚的扩展. 1 JSONView2 Adblock Plus3 Keylines4 彩云小译5 单词发现者6 鼠标 ...
- Redis(3)——分布式锁深入探究
一.分布式锁简介 锁 是一种用来解决多个执行线程 访问共享资源 错误或数据不一致问题的工具. 如果 把一台服务器比作一个房子,那么 线程就好比里面的住户,当他们想要共同访问一个共享资源,例如厕所的时候 ...
- JavaScript学习总结之数组常用的方法和属性
先点赞后关注,防止会迷路寄语:没有一个冬天不会过去,没有一个春天不会到来. 前言数组常用的属性和方法常用属性返回数组的大小常用方法栈方法队列方法重排序方法操作方法转换方法迭代方法归并方法总结结尾 前言 ...
- 得亏了它,我才把潜藏那么深的Bug挖出来
2020年写了很多事故解决的文章,并不是我绞尽脑汁想出来的,而是真的遇到了这些问题.通过文章的方式记录下来,分享出去,才有意义. 事故背景 首先看下面的图吧,这是我从cat上截的图. 可以看到是一个R ...