網上關於Python當中global和nonlocal的作用域講解已經數不勝數了 ,我就拿個實際當中遇到的例子來說事兒,從而來加深一下Python作用域方面知識的印象。
起因是這樣的:我想啓動GUI界面讓客戶選擇一些活動,並把用戶的選擇序列化到本地,同時還希望繼續在內存當中記住用戶的選擇,以便後續繼續使用。
import pickle
import tkinter
app = tkinter.Tk()
def selenium_handler_yingxiao():
all_activity_name = ["西安客經-智慧企業-社區店派單",
"2020西安社區店-單寬轉融營銷",
"西安社區店-賬齡2個月欠費回收"]
try:
activity_record = pickle.load(open('4to5.pckl', 'rb'))
except FileNotFoundError: # 如果文件不存在,新建並重置
print("文件不存在,新建並重置")
activity_record = []
if len(activity_record) == 0: # 如果讀取內容爲空,打開GUI進行設置
op_mark = [tkinter.IntVar() for _ in all_activity_name]
for variable, text in zip(op_mark, all_activity_name):
tkinter.Checkbutton(text=text, variable=variable).pack()
def change():
global activity_record
activity_record = [text for variable, text in zip(op_mark, all_activity_name) if variable.get()]
pickle.dump(activity_record, open('4to5.pckl', 'wb'))
print("我們要呼的活動爲1:", id(activity_record), activity_record)
app.quit()
tkinter.Button(app, text="確認", command=change).pack()
app.mainloop()
print("我們要呼的活動爲2:", id(activity_record), activity_record)
selenium_handler_yingxiao()
print("我們要呼的活動爲:", id(activity_record), activity_record)
我期望兩個活動輸出的東西都是一樣的,但是實際輸出卻是這樣的:
我們要呼的活動爲1: 318160520 ['2020西安社區店-單寬轉融營銷', '西安社區店-賬齡2個月欠費回收']
我們要呼的活動爲2: 318517960 []
我們要呼的活動爲: 318160520 ['2020西安社區店-單寬轉融營銷', '西安社區店-賬齡2個月欠費回收']
爲什麼會出現這種情況呢?
這是因爲函數 change() 中 global activity_record 語句將變量 activity_record 聲明爲全局變量,但是隻要還是在函數selenium_handler_yingxiao() 的作用域裏邊,activity_record就仍然是 selenium_handler_yingxiao() 函數的局部變量。在 selenium_handler_yingxiao()函數的作用範圍以外,我們仍然可以正常獲取到用戶的選擇。
那麼,如果我們想在函數 selenium_handler_yingxiao()末尾正常獲取到用戶選擇的活動,應該要怎麼做呢?
第一種方法:我們可以在 selenium_handler_yingxiao() 函數裏邊聲明變量 activity_record 爲全局變量(global activity_record),這樣,就在兩處地方聲明瞭global activity_record,selenium_handler_yingxiao()裏的變量就變成真正的全局變量了。
import pickle
import tkinter
app = tkinter.Tk()
def selenium_handler_yingxiao():
global activity_record
all_activity_name = ["西安客經-智慧企業-社區店派單",
"2020西安社區店-單寬轉融營銷",
"西安社區店-賬齡2個月欠費回收"]
try:
activity_record = pickle.load(open('4to5.pckl', 'rb'))
except FileNotFoundError: # 如果文件不存在,新建並重置
print("文件不存在,新建並重置")
activity_record = []
if len(activity_record) == 0: # 如果讀取內容爲空,打開GUI進行設置
op_mark = [tkinter.IntVar() for _ in all_activity_name]
for variable, text in zip(op_mark, all_activity_name):
tkinter.Checkbutton(text=text, variable=variable).pack()
def change():
global activity_record
activity_record = [text for variable, text in zip(op_mark, all_activity_name) if variable.get()]
pickle.dump(activity_record, open('4to5.pckl', 'wb'))
print("我們要呼的活動爲1:", id(activity_record), activity_record)
app.quit()
tkinter.Button(app, text="確認", command=change).pack()
app.mainloop()
print("我們要呼的活動爲2:", id(activity_record), activity_record)
selenium_handler_yingxiao()
print("我們要呼的活動爲:", id(activity_record), activity_record)
文件不存在,新建並重置
我們要呼的活動爲1: 68402824 ['2020西安社區店-單寬轉融營銷', '西安社區店-賬齡2個月欠費回收']
我們要呼的活動爲2: 68402824 ['2020西安社區店-單寬轉融營銷', '西安社區店-賬齡2個月欠費回收']
我們要呼的活動爲: 68402824 ['2020西安社區店-單寬轉融營銷', '西安社區店-賬齡2個月欠費回收']
第二種方法:我們可以在函數 change() 裏聲明 nonlocal activity_record,這樣,nonlocal聲明的變量activity_record不是局部變量,也不是全局變量,而是外部嵌套函數 selenium_handler_yingxiao() 內的變量,也就是說,這樣聲明以後,你可以認爲 selenium_handler_yingxiao() 的 activity_record 和內部嵌套函數 change() 的 activity_record 是同一個變量。
import pickle
import tkinter
app = tkinter.Tk()
def selenium_handler_yingxiao():
all_activity_name = ["西安客經-智慧企業-社區店派單",
"2020西安社區店-單寬轉融營銷",
"西安社區店-賬齡2個月欠費回收"]
try:
activity_record = pickle.load(open('4to5.pckl', 'rb'))
except FileNotFoundError: # 如果文件不存在,新建並重置
print("文件不存在,新建並重置")
activity_record = []
if len(activity_record) == 0: # 如果讀取內容爲空,打開GUI進行設置
op_mark = [tkinter.IntVar() for _ in all_activity_name]
for variable, text in zip(op_mark, all_activity_name):
tkinter.Checkbutton(text=text, variable=variable).pack()
def change():
nonlocal activity_record
activity_record = [text for variable, text in zip(op_mark, all_activity_name) if variable.get()]
pickle.dump(activity_record, open('4to5.pckl', 'wb'))
print("我們要呼的活動爲1:", id(activity_record), activity_record)
app.quit()
tkinter.Button(app, text="確認", command=change).pack()
app.mainloop()
print("我們要呼的活動爲2:", id(activity_record), activity_record)
selenium_handler_yingxiao()
# print("我們要呼的活動爲:", id(activity_record), activity_record)
我們要呼的活動爲1: 317439688 ['2020西安社區店-單寬轉融營銷', '西安社區店-賬齡2個月欠費回收']
我們要呼的活動爲2: 317439688 ['2020西安社區店-單寬轉融營銷', '西安社區店-賬齡2個月欠費回收']
當然,這個時候,如果沒有進行特別的return操作,在 selenium_handler_yingxiao() 函數外邊是獲取不到activity_record 變量的。