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 变量的。

猜你喜欢

转载自blog.csdn.net/TomorrowAndTuture/article/details/106563106