Python中的global和nonlocal作用域實例問題

網上關於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 變量的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章