首页 > 代码库 > 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函数要设置参数?
    1.     auth函数中的func  其实就是 index,如上代码,就是func=index,写在括号中跟写在外面一样
    2.  auth这个函数返回的是wrapper ,这是个闭包函数,外面包着auth,引用着index,最后这个闭包函数要执行的话,就得遵循index,如果index是无参函数,那么wrapper就不需要参数,如果有参数,那么wrapper就得跟index一样传入参数,说白了,最后这个闭包函数就是外面包了一层的index,得遵循index的规则

global与nonlocal