首页 > 代码库 > global与nonlocal
global与nonlocal
global与nonlocal:
global关键字:
x=1
def foo():
x=10
print(x) #打印: 10
foo()
print(x) #打印: 1
#############》》》局部的x不会影响全局的x
x=1
def foo(): #使用global关键字,在局部修改全局变量
global x
x=10
print(x) #打印: 10
foo()
print(x) #打印: 10
##########################################################################################################################################
nonlocal关键字:
x=1
def f1():
x=2
def f2():
x=3
def f3():
nonlocal x #使用nonlocal关键字,在局部修改上一层变量,如果内部没有就找不到,不会找全局的
x=10
f3()
print(x) #打印:10
f2()
f1()
print(x) #打印: 1
闭包函数:
定义在函数内部的函数,叫做内部函数
该内部函数包含对外部作用域,而不是对全局作用域名字的引用
特点:
自带作用域
延迟计算
使用:给一个函数包一个状态
name=‘chen‘
def func():
name=‘shuai‘
def bar():
print(name) #用的是name=‘shuai‘
return bar
func() #拿到闭包函数
b=func()
#
# func()返回的是bar的内存地址(其实不仅仅是地址,还包了name的变量),赋值给b, 这个b就是闭包函数
验证是不是闭包函数:>>>>>>>>>>>>>>>>>>>>
print(b.__closure__) ################### 打印: (<cell at 0x0000027692BB7498: str object at 0x0000027692C4C6F8>,) 打印元组,内有一个元素,是闭包函数b外面包的那层作用域的名字 #########################
print(b.__closure__[0].cell_contents) #################看b外面包含的值到底是什么(name=‘shuai‘),[0]取第一个值,打印: shuai ##############
包一层
# 包一层
def wrapper():
money=10000
def tell_info():
print(‘shuai have money %s‘ %(money))
return tell_info
tell_info=wrapper()
def foo():
money=100
tell_info()
foo()
包两层:
#包两层
def aaa():
name=‘shuai‘
def wrapper():
money=1000
def tell_info():
print(‘shuai have money %s‘ %(money))
print(‘my namn is %s‘ %name)
return tell_info
return wrapper
w=aaa()
tell_info=w()
print(tell_info.__closure__[0].cell_contents)
print(tell_info.__closure__[1].cell_contents)
报错NameError: name ‘money‘ is not defined
原因:
函数的作用域关系在函数定义阶段就已经固定,与调用位置无关
无论函数在何处调用,都需要回到定义阶段去找对应的作用域关系
此例:虽然tell_info(‘egon‘)是在foo内调用并且引用money,但仍需要回到定义
tell_info的阶段去找作用域关系,而定义时tell_info引用的money就是全局的money
如果全局不存在则抛出异常NameError
使用例子:
from urllib.request import urlopen
def index(url):
# url=‘http://www.baidu.com/‘
def get():
return urlopen(url).read()
return get
python=index(‘https://www.python.org‘)
print(python())
装饰器:
一:开放封闭原则,对扩展是开放的,对修改是封闭的
二:装饰器,装饰器本质可以是任意可调用对象,被装饰的对象也可以是任意 可调用对象
装饰器的功能是:
在不修改被装饰对象源代码以及调用方式的前提下为期添加新功能
原则:
1.不修改源代码
2.不修改调用方法
目标:添加新功能
装饰器计算运行时间
import time
import random
#装饰器增加计算时间功能
def timmer(func):
# func=index
def wrapper():
start_time = time.time()
func() #index()
stop_time=time.time()
print(‘run time is %s‘ %(stop_time-start_time))
return wrapper
#被装饰函数
def index():
time.sleep(random.randrange(1,5))
print(‘welecome to index page‘)
def home():
time.sleep(random.randrange(1,3))
print(‘welecome to HOME page‘)
index=timmer(index) #index=wrapper
home=timmer(home)
装饰器的语法:在被装饰对象的正上方的单独一行,@装饰器名字
# import time
# import random
# #装饰器
# 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
# #被装饰函数
# @timmer #index=timmer(index)
# def index():
# time.sleep(random.randrange(1,5))
# print(‘welecome to index page‘)
# # @timmer #home=timmer(home)
# # def home():
# # time.sleep(random.randrange(1,3))
# # print(‘welecome to HOME page‘)
#
# index() #wrapper()
# # home()
#加多个装饰器
import time
import random
#装饰器
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 auth(func):
def deco():
name=input(‘name: ‘)
password=input(‘password: ‘)
if name == ‘egon‘ and password == ‘123‘:
print(‘login successful‘)
func() #wrapper()
else:
print(‘login err‘)
return deco
#被装饰函数
@auth #index=auth(wrapper) #index=deco #index=auth(wrapper) #index=deco
@timmer #index=timmer(index) #index=wrapper
def index():
# time.sleep(random.randrange(1,5))
time.sleep(3)
print(‘welecome to index page‘)
def home():
time.sleep(random.randrange(1,3))
print(‘welecome to HOME page‘)
# index() #deco()
# home()
装饰器语法:@
1 写在被装饰对象的正上方单独一行
2 可以叠加多个,
定义阶段外部函数的执行顺序是自下而上
调用阶段内部函数的执行顺序是自上而下
(@timmer加上边就是先计时,再验证 ; @auth加上边就是先验证再计时)
练习:
编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
注意:从文件中读出字符串形式的字典,可以用eval(‘{"name":"egon","password":"123"}‘)转成字典格式
user_dic={ #用字典存用户信息
‘chen‘:‘123‘,
‘shuai‘:‘454‘,
‘yuan‘:‘363‘,
‘fang‘:‘123123‘
}
with open(‘db.txt‘,‘w‘,encoding=‘utf-8‘) as f: # 创建文件db.txt,把user_dic以文本模式写入 db.txt
f.write(str(user_dic)) # 文本模式写的是字符,不能写字典,必须写字符串形式
with open(‘db.txt‘,‘r‘,encoding=‘utf-8‘) as f: # 读文件的内容,读出的结果是字符串
res=f.read()
# print(res,type(res)) # 是字符串,包含了想要的字典
user_dic=eval(res) # eval(res) 提出字符串包含的东西(也就是那个字典)
print(user_dic,type(user_dic)) # 输出了字典
db_path=r‘C:\Users\Administrator\PycharmProjects\python5期\day8\db.txt‘
login_dic={
‘user‘:None,
‘status‘:False,
}
def auth(func): # func=index 传入index
####def wrapper(*args,**kwargs): #这是原始的写法,在wrapper中调用外部的func,func就是index,返回 执行结果
###res=func(*args,**kwargs)
###return res
def wrapper(*args,**kwargs): #有参数的话这里需要接受参数,
if login_dic[‘user‘] and login_dic[‘status‘]:
res = func(*args, **kwargs) #有返回值就返回需要的值,没有就返回None,这里是执行原始的index
return res
name=input(‘your name: ‘)
password=input(‘your password: ‘)
with open(db_path,‘r‘,encoding=‘utf-8‘) as f:
user_dic=eval(f.read())
if name in user_dic and password == user_dic[name]:
print(‘login ok‘)
login_dic[‘user‘]=name
login_dic[‘status‘]=True
res=func(*args,**kwargs)
return res
else:
print(‘login err‘)
return wrapper
@auth #auth(index) ## 执行index 把index传入装饰器 auth
def index():
print(‘welecome to index‘)
@auth
def home(name): ## 执行home 把home传入装饰器 aurh home是有参数的,所以上边wrapper要有参数
print(‘welecome %s to home page‘ %name)
index()
home(‘chen‘)
五:编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
‘‘‘
from urllib.request import urlopen
import os
cache_path=r‘C:\Users\Administrator\PycharmProjects\python5期\day8\cache.txt‘
def make_cache(func):
def wrapper(*args,**kwargs):
if os.path.getsize(cache_path):
#有缓存
print(‘\033[45m=========>有缓存\033[0m‘)
with open(cache_path,‘rb‘) as f:
res=f.read()
else:
res=func(*args,**kwargs) #下载
with open(cache_path,‘wb‘) as f: #制作缓存
f.write(res)
return res
return wrapper
@make_cache
def get(url):
return urlopen(url).read()
# print(‘================>first‘)
# print(get(‘https://www.python.org‘))
# print(‘================>second‘)
# print(get(‘https://www.python.org‘))
# print(‘================>third‘)
# print(get(‘https://www.python.org‘))
缓存多个不同网站的内容:
#思路:hash每个url,用得到的值做成文件名,一个网站一个文件名,
# 然后每次根据传进来的url进行hash得到的结果去寻找文件
#
# s=‘hello 123‘
# print(hash(s))
# s=‘hello 123‘
# print(hash(s))
def f1():
print(‘from f1‘)
def f2():
print(‘from f2‘)
def f3():
print(‘from f3‘)
func_dic={
‘f1‘:f1,
‘f2‘:f2,
‘f3‘:f3
}
while True:
cmd=input(‘>>:‘).strip()
if cmd in func_dic:
func_dic[cmd]()
func_dic={}
def deco(key):
def deco2(func):
func_dic[key]=func
return deco2
@deco(‘f1‘)
def f1():
print(‘from f1‘)
@deco(‘f2‘)
def f2():
print(‘from f2‘)
@deco(‘f3‘)
def f3():
print(‘from f3‘)
print(func_dic)
while True:
cmd=input(‘>>:‘).strip()
if cmd in func_dic:
func_dic[cmd]()
理解:
def auth(func): # func=index 传入index
####def wrapper(*args,**kwargs): #这是原始的写法,在wrapper中调用外部的func,func就是index,返回 执行结果
###res=func(*args,**kwargs)
###return res
def wrapper(*args,**kwargs): #有参数的话这里需要接受参数,
if login_dic[‘user‘] and login_dic[‘status‘]:
res = func(*args, **kwargs) #有返回值就返回需要的值,没有就返回None,这里是执行原始的index
return res
......
return wrapper
这块代码中,为什么wrapper函数要设置参数?
- auth函数中的func 其实就是 index,如上代码,就是func=index,写在括号中跟写在外面一样
- auth这个函数返回的是wrapper ,这是个闭包函数,外面包着auth,引用着index,最后这个闭包函数要执行的话,就得遵循index,如果index是无参函数,那么wrapper就不需要参数,如果有参数,那么wrapper就得跟index一样传入参数,说白了,最后这个闭包函数就是外面包了一层的index,得遵循index的规则
global与nonlocal
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。