Python的学习之旅———函数对象函数嵌套名称空间与作用域装饰器
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python的学习之旅———函数对象函数嵌套名称空间与作用域装饰器相关的知识,希望对你有一定的参考价值。
一 函数对象
1 可以被引用
2 可以当作参数传递
3 返回值可以是函数
4 可以当作容器类型的元素
1 def foo(): 2 print(‘from foo‘) 3 4 func=foo 5 6 print(foo) 7 print(func) 8 func()
名称空间:存放名字的地方,准确的说名称空间是存放名字与变量值绑定关系的地方
一、名称空间又分为:
内置名称空间:在python解释器启动时产生,存放一些python内置的名字
全局名称空间:在执行文件时产生,存放文件级别定义的名字
局部名称空间:在执行文件的过程中,如果调用了函数,则会产生该函数的局部名称空间
用来存放该函数内定义的名字,该名字在函数调用时生效,在函数调用结束后失效
二、加载顺序
加载顺序:内置--->全局--->局部
三、名字的查找顺序
局部->全局->内置
四、作用域
定义:作用的范围
一、分为
全局作用域:全局存活,全局有效:可以用globals()查看
局部作用域:临时存活,局部有效可以用locals()查看
二、改变全局变量
1、可以用global在局部改变全局变量
声明全局变量,如果在局部要对全局变量修改,需要在局部也要先声明该全局变量:
2、可变变量可以不需要global在函数内进行修改
l=[] def f2(): l.append(‘f2‘) f2() print(l)
3、、nonlocal关键字用来在函数或其他作用域中使用外层(非全局)变量
三、作用域关系
在函数定义时就已经固定于调用位置无关,在调用函数时,必须回到函数原来定义的位置去找作用域关系
LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
locals是函数内的名字空间,包括局部变量和形参
enclosing 外部嵌套函数的名字空间(闭包中常见)
globals 全局变量,函数定义所在模块的名字空间
builtins 内置模块的名字空间
四 闭包函数
内部函数包含外部作用域而非全局作用域的引用。
闭包函数的依据是,函数内部未找到变量相应的值时,会先向上一级函数中寻找
变量值。
二 闭包的意义与应用
为了装饰器做准备 (我是这么觉得的)
五 装饰器
装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
强调装饰器的原则:
1 不修改被装饰对象的源代码
2 不修改被装饰对象的调用方式
装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能
装饰器的原则:在不修改函数调用方式 和函数本身代码的情况下。增加新功能开放封闭原则,对扩展是开放的,对修改是封闭的。
无参装饰器
1 import time 2 3 def timmer(func): 4 # func=index #最原始的index函数的内存地址 5 def inner(): 6 start_time=time.time() 7 func() 8 stop_time=time.time() 9 print(‘run time is :[%s]‘ %(stop_time-start_time)) 10 return inner 11 12 @timmer #index=timmer(index) 13 def index(): 14 time.sleep(3) 15 print(‘welcome to index page‘) 16 index()
有几点是关键 代码在执行到@timmer 做了两件事1将 index()函数名‘index’传给timmer 于是有了 timmer(index),2将timmer()赋值给了 index,(在python中变量名是可以反复使用的,这种操作我觉得就是死皮赖脸的做到调用方式不变的目的)index=timmer()
timmer是一个闭包函数,所以有了 4 # func=index #最原始的index函数的内存地址 因为有闭包函数的特性,所以inner在内部的函数func()在寻找func值的时候会向上一层寻找
于是找到了 func=index。这样就有了inner()内部函数 func()变成了 index(),而inner函数最后又将自己return给timmer()
这时index=timmer()实际上=inner 此时 @timmer的任务就完成了,代码直接跳到16行进行index() 此时的index()==inner().
接下来的顺序 5 -6-7-14-15-8-9.
装饰器修订
1 import time 2 from functools import wraps 3 4 def timmer(func): 5 @wraps(func) #help等功能 6 def inner(*args,**kwargs): 7 start_time=time.time() 8 res=func(*args,**kwargs) 9 stop_time=time.time() 10 print(‘run time is :[%s]‘ %(stop_time-start_time)) 11 return res 12 13 return inner 14 @timmer 15 def index(): 16 ‘‘‘ 17 index function 18 :return: 19 ‘‘‘ 20 time.sleep(3) 21 print(‘welcome to index page‘) 22 return 123 23 24 @timmer #home=timmer(home) #home=inner 25 def home(name): 26 time.sleep(2) 27 print(‘welcome %s to home page‘ %name) 28 return 456
有参装饰器
1 import time 2 current_status={‘user‘:None,‘login_status‘:False} 3 def auth(egine=‘file‘): 4 # egine=‘file‘ 5 def wrapper(func): 6 def inner(*args,**kwargs): 7 if current_status[‘user‘] and current_status[‘login_status‘]: 8 res = func(*args, **kwargs) 9 return res 10 11 if egine == ‘file‘: 12 u=‘egon‘ 13 p=‘123‘ 14 elif egine == ‘mysql‘: 15 print(‘mysql auth‘) 16 u = ‘egon‘ 17 p = ‘123‘ 18 elif egine == ‘ldap‘: 19 print(‘ldap auth‘) 20 else: 21 pass 22 name = input(‘username>>:‘).strip() 23 pwd = input(‘password>>:‘).strip() 24 if name == u and pwd == p: 25 print(‘login successfull‘) 26 current_status[‘user‘] = name 27 current_status[‘login_status‘] = True 28 res = func(*args, **kwargs) 29 return res 30 return inner 31 return wrapper 32 @auth(egine=‘ldap‘) #@wrapper #index=wrapper(index) #index=inner 33 def index(): 34 time.sleep(3) 35 print(‘welcome to index page‘) 36 return 123
wrapper 是无参装饰器,现在wrapper内部需要参数egine,所以需要想办法给egine传参,那么我们就用到了闭包函数.wrapper外面再包一个参数,于是有了auth(egine) ,装饰的时候会写为
@auth(egine) 上面代码写成@auth(egine=‘file‘),只是给了一个默认的初始值.在运行代码时候,见到@auth(egine=‘file‘) 先忘了他是装饰器 先执行auth(egine=‘file‘)函数 于是得到了return出来的wrapper 于是有了@wrapper 也就是我们的无参装饰器.
所以有参装饰器的本质 就是无参装饰器的闭包函数.装饰器最多是三层就够了.
装饰器是有顺序的.修饰下面的代码(如果下面还有多个装饰器).
有参装饰器有三层
1外层 传参给内部的核心功能
2 中层 作用不改变被装饰函数调用方式
3 核心层 是内部功能层
以上是关于Python的学习之旅———函数对象函数嵌套名称空间与作用域装饰器的主要内容,如果未能解决你的问题,请参考以下文章