本文共 5000 字,大约阅读时间需要 16 分钟。
网上关于Python当中global和nonlocal的作用域讲解已经数不胜数了 ,我就拿个实际当中遇到的例子来说事儿,从而来加深一下Python作用域方面知识的印象。
起因是这样的:我想启动GUI界面让客户选择一些活动,并把用户的选择序列化到本地,同时还希望继续在内存当中记住用户的选择,以便后续继续使用。
import pickleimport tkinterapp = 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 pickleimport tkinterapp = 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 pickleimport tkinterapp = 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 变量的。
转载地址:http://edjqi.baihongyu.com/