1. 程式人生 > >global與nonlocal

global與nonlocal

word 結果 練習 輸入 思路 調用 args read second

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