名称空间与作用域、闭包函数、 装饰器
6.7 名称空间与作用域
内置名称空间:
存放的是:内置的名字与值的绑定关系
生效:python解释器启动
失效:Python解释器关闭全局名称空间:
存放的是:文件级别定义的名字与值的绑定
生效:执行python文件时,将该文件级别定义的名字与值的绑定关系存放起来
失效:文件执行完毕局部名称空间:
存放的是:函数内部定义的名字与值的绑定关系
生效:调用函数时,临时生效
失效:函数调用结束
#python test.py
#1、python解释器先启动,因而首先加载的是:内置名称空间
#2、执行test.py文件,然后以文件为基础,加载全局名称空间
#3、在执行文件的过程中如果调用函数,则临时产生局部名称空间加载顺序:内置---》全局----》局部名称空间
访问名字的顺序:局部名称空间===》全局----》内置
x=1 #全局变量 print(x) print(max) #内置变量 max=2 #全局变量 def func(): # max=1 #局部变量 print(max) func() x='gobal' #全局变量 def f1(): # x=1 #局部变量 def f2(): # x=2 #局部变量 def f3(): # x=3 #局部变量 print(x) f3() f2() f1()
全局作用域(全局范围):内置名称空间与全局名称空间的名字,全局存活,全局有效,globals()
局部作用域(局部范围):局部名称空间的名字,临时存活,局部有效,locals()
查看作用域:globals(),locals()
LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
locals 是函数内的名字空间,包括局部变量和形参
enclosing 外部嵌套函数的名字空间(闭包中常见) #f2()上有f1(),下有f3()
globals 全局变量,函数定义所在模块的名字空间
builtins 内置模块的名字空间
xxx=11111 print(globals()) #打印全局变量和内置变量 print(dir(globals()['__builtins__'])) #查看内置变量 print(locals() is globals()) #true def func(): yyyyyyyyyyyyyyyyyyyyyyyy=22222222 print(globals()) #打印全局变量和内置变量 print(locals()) #查看局部变量 func()
global: 关键字用来在函数或其他局部作用域中使用全局变量。但是如果不修改全局变量也可以不使用global关键字。
x=100 def func(): global x #在函数内调用全局变量 x=1 func() print(x)
nonlocal:关键字用来在函数或其他作用域中使用外层(非全局)变量。函 数内部一层一层往上找,没有则报错
x='global' def f1(): x=1 def f2(): nonlocal x #调用外层(非全局)变量 x=0 f2() print('===f1 innter--->',x) f1() print(x)
强调两点:
1、打破函数层级限制来调用函数
2、函数的作用域关系是在函数定义阶段就已经固定了,与调用位置无关
x=1 def outter(): x=2 def inner(): print('inner',x) return inner f=outter() def bar(): x=3 f() bar() # 执行结果:inner 2
6.8 闭包函数
闭包函数:
1 定义在函数内部的函数
2 该函数的函数体代码包含对外部作用域(而不是全局作用域)名字的引用
3 通常将闭包函数用return返回,然后可以在任意使用
z=1 def outer(): x=1 y=2 def inner(): #闭包函数 print(x,y) return inner f=outer() print(f.__closure__[0].cell_contents) # 1 print(f.__closure__[1].cell_contents) # 2 print(f.__closure__) #(<cell at 0x00000000026D65B8: int object at 0x0000000054FBC6B0>, <cell at 0x00000000026D65E8: int object at 0x0000000054FBC6D0>) def bar(): x=111121 y=2222 f() bar()
应用:
爬页面:闭包函数为我们提供了一种新的为函数传参的方式
import requests #pip3 install requests def outter(url): # url = 'https://www.baidu.com' def get(): response=requests.get(url) if response.status_code == 200: print(len(response.text)) return get baidu=outter('https://www.baidu.com') python=outter('https://www.python.org') baidu() python() baidu ()
6.9 装饰器
6.9.1 无参装饰器
开放封闭原则:对扩展开放,对修改是封闭
装饰器:装饰它人的,器指的是任意可调用对象,现在的场景装饰器-》函数,被装饰的对象也是-》函数
原则:1、不修改被装饰对象的源代码
2、不修改被装饰对象的调用方式
装饰器的目的:在遵循1,2的前提下为被装饰对象添加上新功能
# 错误的示范,改变了调用方式 import time def index(): time.sleep(3) print('welecome to index') def timmer(func): start=time.time() func() stop=time.time() print('run time is %s' %(stop-start)) timmer(index)
# 正确但不完善 import time def index(): time.sleep(3) print('welecome to index') def timmer(func): # func=index #最原始的index def inner(): start=time.time() func() #最原始的index stop=time.time() print('run time is %s' %(stop-start)) return inner index=timmer(index) #index=inner # print(f) index() #inner()
装饰器语法:在被装饰对象正上方单独一行写上,@装饰器名
#改进一: import time def timmer(func): def inner(): start=time.time() res=func() stop=time.time() print('run time is %s' %(stop-start)) return res return inner @timmer #index=timmer(index) def index(): time.sleep(1) print('welecome to index') return 1111 res=index() #res=inner() print(res) #改进二: import time def timmer(func): def inner(*args,**kwargs): start=time.time() res=func(*args,**kwargs) stop=time.time() print('run time is %s' %(stop-start)) return res return inner @timmer #index=timmer(index) def index(name): time.sleep(1) print('welecome %s to index' %name) return 1111 res=index('egon') #res=inner('egon') print(res)
6.9.2 有参装饰器
import time def auth2(engine='file'): def auth(func): # func=index def inner(*args,**kwargs): if engine == 'file': name=input('name>>: ').strip() password=input('password>>: ').strip() if name == 'egon' and password == '123': print('login successful') return func(*args,**kwargs) else: print('login err') elif engine == 'mysql': print('mysql auth') elif engine == 'ldap': print('ldap auth') else: print('engin not exists') return inner return auth @auth2(engine='mysql') #@auth #index=auth(index) #index=inner def index(name): time.sleep(1) print('welecome %s to index' %name) return 1111 res=index('egon') #res=inner('egon') print(res)
6.9.3 并列多个装饰器
import time def timmer(func): def inner(*args,**kwargs): start=time.time() res=func(*args,**kwargs) stop=time.time() print('run time is %s' %(stop-start)) return res return inner def auth2(engine='file'): def auth(func): # func=index def inner(*args,**kwargs): if engine == 'file': name=input('name>>: ').strip() password=input('password>>: ').strip() if name == 'egon' and password == '123': print('login successful') return func(*args,**kwargs) else: print('login err') elif engine == 'mysql': print('mysql auth') elif engine == 'ldap': print('ldap auth') else: print('engin not exists') return inner return auth @auth2(engine='file') #多个装饰器 @timmer def index(name): time.sleep(1) print('welecome %s to index' %name) return 1111 res=index('egon') print(res)
6.9.4 wraps补充
wraps: 让被装饰的函数,使用help()是看到的信息也是被装饰函数的帮助信息。
from functools import wraps #导入模块 import time def timmer(func): @wraps(func) #使用 wraps装饰 def inner(*args,**kwargs): start=time.time() res=func(*args,**kwargs) stop=time.time() print('run time is %s' %(stop-start)) return res # inner.__doc__=func.__doc__ # inner.__name__=func.__name__ return inner @timmer def index(name): #index=inner '''index 函数。。。。。''' #index函数的帮助信息 time.sleep(1) print('welecome %s to index' %name) return 1111 # res=index('egon') # print(res) print(help(index))