迭代 装饰器 闭包
迭代器:
包含yield表达式的函数是特殊的函数,叫做生成器函数(generator function),被调用时将返回一个迭代器(iterator),调用时可以使用next或send(msg)。它的用法与return相似,区别在于它会记住上次迭代的状态,继续执行。
send(msg)与next()的区别在于send可以传递参数给yield表达式,这时传递的参数会作为yield表达式的值,而yield的参数是返回给调用者的值。初始调用时必须先next()或send(None),否则会报错。
举个例子:
首先生成一个迭代器f,f.next()会使生成器函数执行到yield,生成一个值然后挂起。
然后f.next()或f.send(msg)会在生成器函数内部返回值,执行到下一个yield,生成值后挂起
然后f.next()或f.send(msg)会在生成器函数内部返回值,意图执行到下一个yield,但是后面没有yield了,所以抛出异常。
使用yield可以有效简化代码,并减少空间浪费。
举个简单例子:列表中的每个元素+1
传统写法:
Python代码
- def addlist(alist):
- r = []
- for i in alist:
- r.append(i+1)
- return r
复制代码
yield写法:
Python代码
- def addlist(alist):
- for i in alist:
- yield i + 1
复制代码
当然对于这种简单的问题:
Python代码
- [i+1 for i in alist]
复制代码
1、定义:假设我们要增强一个函数的功能,比如,在函数调用前后自动打印日志,但又不希望改变这个函数的源代码,这种在代码运行期间动态增加功能且又不改变源代码的方式,成为装饰器(Decorator)。本质上,decorator就是一个返回函数的高阶函数
2、示例:
如上图中的原函数为index(),我们通过装饰器为其增加了一个计算运行时间的功能,但是没有改变源代码,这就是为其增加了一个装饰器,装饰器的功能就是计时。
关键点:@的语法,@timmer等同于进行了如下操作:index=timmer(index),函数名+()就是调用函数,一定要记住!!好多地方想不通原因就是在这里!
思想就是把部内函数func()换成被装饰函数index()然后再运行闭包函数就好了(可能说的有点简单)
3、复杂一点的例子,代参数的,并且是用于多个参数不确定的函数的装饰器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
import time
def timmer(func):
def wrapper ( * args, * * kwargs): ##注意注意*args和**kwargs
start_time = time.time()
func( * args, * * kwargs) ##注意注意*args和**kwargs
stop_time = time.time()
print ( "run time is %s" % (stop_time - start_time))
return wrapper
@timmer ##注意注意位于被装饰函数最上方,且单独占一行
def home(name):
time.sleep( 2 )
print ( "welcome to %s home page" % name)
@timmer
def auth(name,password):
print (name,password)
@timmer
def tell():
print ( '=======' )
home( 'dragon' )
auth( 'egon' , '123' )
tell()
|
4、装饰用户认证功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#现在是对index()函数增加了用户认证功能,源代码没有变<br>def auth2(auth_type):
def auth(func):
def wrapper( * args, * * kwargs):
if auth_type = = 'file' :
name = input ( 'username:' )
password = input ( 'password:' )
if name = = 'zhejiangf4' and password = = 'sbasb' :
print ( 'auth successful' )
res = func( * args, * * kwargs)
return res
else :
print ( 'auth error' )
elif auth_type = = "sql" :
print ( "还他妈不会玩" )
return wrapper
return auth
@auth2 (auth_type = "file" ) #==>@auth==>index=auth(index),所以auth2作用就是传了一个值
def index():
print ( 'Welcome to index page!' )
index()
|
5、再给上面的函数加一个时间模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
import time
def timmer(func):
def wrapper():
start_time = time.time()
func()
stop_time = time.time()
print (stop_time - start_time)
return wrapper
def auth2(auth_type):
def auth(func):
def wrapper( * args, * * kwargs):
if auth_type = = 'file' :
name = input ( 'username:' )
password = input ( 'password:' )
if name = = 'zhejiangf4' and password = = 'sbasb' :
print ( 'auth successful' )
res = func( * args, * * kwargs)
return res
else :
print ( 'auth error' )
elif auth_type = = "sql" :
print ( "还他妈不会玩" )
return wrapper
return auth
@timmer
@auth2 (auth_type = "file" ) #
def index():
print ( 'Welcome to index page!' )
index()
|
上面函数的运行原理需要细说一下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
#先把大体的概念说一下:
# def aaa():#装饰函数
# @aaa
# def func():#被装饰函数
# pass
#
# func=aaa(func)
# @ccc
# @bbb
# @aaa
# def func():
# pass
#
# func=ccc(bbb(aaa(func)))
#
# @ccc('c')
# @bbb('b')
# @aaa('a')
# def func():
# pass
#
# func=ccc('c')(bbb('b')(aaa('a')(func)))
#上边的例子是下边这个规律
#founc=bbb(aaa('a')(func))
#index=timmer(auth2(auth_type="list")(func))
#index=timmer(auth(func))
#index=timmer(wrapper_dixia)
#index=wrapper_shangbian
#index()=wrapper_shangbian()
#index()=wrapper_dixia()
|
6、eval函数:会把字符串里面的东西读出来执行,结果必须要赋值,不然砸电脑
1
2
3
4
5
6
7
8
9
|
m = input ( ">>:" )
m = eval (m)
print (m, type (m))
>>:{ "name" : "agon" }
{ 'name' : 'agon' } < class 'dict' >
>>:[ "agon" ]
[ 'agon' ] < class 'list' >
>>: print ( 123 )
|
7、给认证装饰器增加一个登陆后再次调用是免认证的功能(字典,只在内存中能行)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
import time
current_login = { 'name' : None , 'login' : False } #建立一个字典,字典存储登录状态
def timmer(func):
def wrapper():
start_time = time.time()
func()
stop_time = time.time()
print ( 'run time is %s' % (stop_time - start_time))
return wrapper
def auth2(auth_type = 'file' ):
def auth(func):
def wrapper( * args, * * kwargs):
if current_login[ 'name' ] and current_login[ 'login' ]: #判断状态是否被激活,若激活直接执行函数结束
res = func( * args, * * kwargs)
return res
if auth_type = = 'file' :
name = input ( 'username:' )
password = input ( 'password:' )
if name = = 'zhejiangF4' and password = = 'sb945' :
print ( 'auth successful' )
res = func( * args, * * kwargs)
current_login[ 'name' ] = name #存储登录状态
current_login[ 'login' ] = True
return res
else :
print ( 'auth error' )
elif auth_type = = "sql" :
print ( "haibuhui" )
return wrapper
return auth
@timmer
@auth2 (auth_type = "file" )
def index():
print ( 'welcome to index page' )
@auth2 ( "file" )
def home():
print ( "welcome to home page" )
index()
home() #第一次执行index()函数是需要登录认证,但第二次执行home时就不需要再认证了
|
8、怎样在增加装饰器后还可以打印原函数的注释内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import time
from functools import wraps #从函数工具中调用wraps模块
def timmer(func):
@wraps (func) #它就可以让你打印出的index.__doc__编程原函数的"dashabi"而不是wrapper函数的"000"
def wrapper( * args, * * kwargs):
'000'
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
def index():
"dashabi"
print ( "from index" )
index()
print (index.__doc__)
|
闭包
闭包并不是什么新奇的概念,它早在高级语言开始发展的年代就产生了。闭包(Closure)是词法闭包(Lexical Closure)的简称。对闭包的具体定义有很多种说法,这些说法大体可以分为两类:
一种说法认为闭包是符合一定条件的函数,比如参考资源中这样定义闭包:闭包是在其词法上下文中引用了自由变量的函数。
另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。比如参考资源中就有这样的的定义:在实现深约束时,需要创建一个能显式表示引用环境的东西,并将它与相关的子程序捆绑在一起,这样捆绑起来的整体被称为闭包。
就像这样:
#python 中的闭包 ... def func(data): ... count = [data] ... def wrap(): ... count[0] += 1 ... return count[0] ... return wrap ... ... a = func(1) >>> a() 5: 2 >>> a() 6: 3def func(x): ... return lambda y :y+x >>> b = func(1) >>> b(1) 7: 2 >>> b(2) 8: 3 >>> print b #这里b是个function 在ruby中是proc <function <lambda> at 0x01AC68F0>def addx(x): ... def adder (y): return x + y ... return adder >>> add8 = addx(8) >>> add8(8) 9: 16
简单说,闭包就是根据不同的配置信息得到不同的结果
python实例
看概念总是让人摸不着头脑,看几个python小例子就会了
例1
def make_adder(addend):def adder(augend):return augend + addendreturn adderp = make_adder(23) q = make_adder(44)print p(100) print q(100)
运行结果:
123
144
分析一下:
我们发现,make_adder是一个函数,包括一个参数addend,比较特殊的地方是这个函数里面又定义了一个新函数,这个新函数里面的一个变量正好是外部make_adder的参数.也就是说,外部传递过来的addend参数已经和adder函数绑定到一起了,形成了一个新函数,我们可以把addend看做新函数的一个配置信息,配置信息不同,函数的功能就不一样了,也就是能得到定制之后的函数.
再看看运行结果,我们发现,虽然p和q都是make_adder生成的,但是因为配置参数不同,后面再执行相同参数的函数后得到了不同的结果.这就是闭包.
例2
def hellocounter (name):count=[0] def counter():count[0]+=1print 'Hello,',name,',',str(count[0])+' access!'return counterhello = hellocounter('ma6174') hello() hello() hello()
执行结果
Hello, ysisl , 1 access!
Hello, ysisl , 2 access!
Hello, ysisl , 3 access!
分析一下
这个程序比较有趣,我们可以把这个程序看做统计一个函数调用次数的函数.count[0]可以看做一个计数器,没执行一次hello函数,count[0]的值就加1。也许你会有疑问:为什么不直接写count而用一个列表?这是python2的一个bug,如果不用列表的话,会报这样一个错误:
UnboundLocalError: local variable 'count' referenced before assignment.
什么意思?就是说conut这个变量你没有定义就直接引用了,我不知道这是个什么东西,程序就崩溃了.于是,再python3里面,引入了一个关键字:nonlocal,这个关键字是干什么的?就是告诉python程序,我的这个count变量是再外部定义的,你去外面找吧.然后python就去外层函数找,然后就找到了count=0这个定义和赋值,程序就能正常执行了.
python3 代码
def hellocounter (name):count=0 def counter():nonlocal countcount+=1print 'Hello,',name,',',str(count[0])+' access!'return counterhello = hellocounter('ma6174') hello() hello() hello()
例3
def makebold(fn):def wrapped():return "<b>" + fn() + "</b>"return wrappeddef makeitalic(fn):def wrapped():return "<i>" + fn() + "</i>"return wrapped@makebold @makeitalic def hello():return "hello world"print hello()
执行结果
<b><i>hello world</i></b>
简单分析
怎么样?这个程序熟悉吗?这不是传说的的装饰器吗?对,这就是装饰器,其实,装饰器就是一种闭包,我们再回想一下装饰器的概念:对函数(参数,返回值等)进行加工处理,生成一个功能增强版的一个函数。再看看闭包的概念,这个增强版的函数不就是我们配置之后的函数吗?区别在于,装饰器的参数是一个函数或类,专门对类或函数进行加工处理。
python里面的好多高级功能,比如装饰器,生成器,列表推到,闭包,匿名函数等,开发中用一下,可能会达到事半功倍的效果!
以上三篇博文分别转载于
http://blog.csdn.net/orangleliu/article/details/8752058
http://www.cnblogs.com/wuyongqiang/p/6690004.html
http://www.jb51.net/article/70897.htm
转载于:https://www.cnblogs.com/QQ_86053634/p/6956810.html
迭代 装饰器 闭包相关推荐
- 装饰器 闭包 生成器 迭代器
2018-02-21 16:15:56 定义:本质是函数,(装饰其他函数)为其他函数增加附加功能 装饰器原则 不能修改被装饰函数的源代码 不能修改被装饰函数的调用方式 说白了,就是被装饰函数不知道装 ...
- 装饰器,闭包,高阶函数,嵌套函数
高阶函数代码形式:(1.函数接收的参数是一个函数名 2.函数的返回值是一个函数名) def too():print('from too') #高阶函数 def foo():print('from fo ...
- 第十章 设计模式/垃圾回收/装饰器/闭包
目录 一.设计模式 1.1 单例模式 1.2 工厂模式 1.3 抽象工厂模式 1.4 建造者 1.5 原型 二.垃圾回收 三.装饰器 3.1 变量作用域 3.2 变量解析规则 3.3 变量生存空间 3 ...
- python闭包与装饰器----闭包
形成闭包的条件: 1.必须要有一个内嵌函数 2.内函数必须引用外函数的变量 3.外函数必须返回内函数 (变量解析原则是LEGB 本地.内嵌.全局.内建) 形成闭包之后闭包函数会得到一个非空的" ...
- Python中的装饰器、迭代器、生成器、推导式、匿名函数和高阶函数
文章目录 装饰器 迭代器 生成器 推导式 匿名函数 高阶函数 装饰器 闭包 介绍装饰器前先了解一下闭包,在Python中,一切皆对象(Object),函数(Function)也不例外,也是一个普通的对 ...
- python修饰器classmate_[python基础]装饰器、迭代器、生成器
装饰器 装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象 它经常用于有切面需求的场景,比如:插入日志.性能测试.事务处理. ...
- python装饰器类-PYTHON里的装饰器能装饰类吗
扩展回答 如何理解python里的装饰器 通常可以理解它是一个hook 的回调函数. 或者是理解成python 留给二次开发的一个内置API. 一般是用回调和hook 方式实现的. 如何理解Pytho ...
- python类装饰器详解-python 中的装饰器详解
装饰器 闭包 闭包简单的来说就是一个函数,在该函数内部再定义一个函数,并且这个内部函数用到了外部变量(即是外部函数的参数),最终这个函数返回内部函数的引用,这就是闭包. def decorator(p ...
- 【python】装饰器
装饰器模式定义:动态地给一个对象添加一些额外的职责. 比如一个函数或者接口,你不想修改它,又想添加一些额外的功能 def aaa (): print("苹果,西瓜,火龙果") de ...
最新文章
- Java IO: 管道
- slimphp中间件调用流程的理解
- 树的高度 递归法和非递归法
- Android 仿QQ消息界面
- 移动互联网这十年,跨平台技术的演进及 Flutter 的未来
- 极域电子书包课堂管理系统怎么控屏_极域电子教室使用方法
- 图文详解教你在线换系统(无须U盘)
- css3boder-image属性使用
- 入门物联网还得靠嵌入式
- metro样式开机启动菜单_如何在Windows 8中获取Metro风格的开始菜单和开始按钮
- SAS Planet+ArcGIS
- 如何查看笔记本电脑的型号?
- 二维码是如何设计出来的?
- 全球最大双机身飞机Stratolaunch完成首飞
- 2022西藏最新建筑八大员(劳务员)模拟试题题库及答案
- PS 2019 Mac版 自学入门系列(十一)—— 创建光照效果
- android加密参数定位方法
- 抖音测试的软件,抖音app测试版
- keil5重新建工程出现Error: Flash Download failed - Could not load fil
- 计算机网络03:数据链路层