我正在尝试使用Python 3.3.0上的Tkinter为简单的应用程序构建GUI。 我偶然发现了一个有点编程的怪癖,乍一看似乎是错的。虽然它不是本身的问题(它不影响我的目标)但它在Pythonic方式中没有意义。
所以,这是来源:
from tkinter import *
from tkinter import ttk
def foo():
def bar():
root.destroy()
root = Tk()
mainframe = ttk.Frame(root).grid(column=0, row=0)
ttk.Button(mainframe,text="Goodbye",command=bar).grid(column=1, row=1)
root.mainloop()
foo()
运行此按钮并单击"Goodbye"
按钮会关闭窗口,正如预期的那样......但是这里存在问题。如果我运行这个简化版本的代码:
def foo():
def bar():
hee = "spam"
hee = "eggs"
print(hee)
bar()
print(hee)
foo()
>>> eggs
>>> eggs
我无法访问hee
中定义的foo()
,并在hee
中创建新的bar()
。如果我现在要将nonlocal hee
添加到bar()
def的开头,则输出:
>>> eggs
>>> spam
将是预期的。
所以,我的问题是为什么我能够在第一个例子中调用root
对象而不首先声明它是非本地的?
答案 0 :(得分:0)
根据Short Description of Python Scoping Rules(另请参阅The Python Tutorial),对象名称范围解析符合LEGB规则(本地,附加函数,全局,内置函数)。
话虽如此,以下示例举例说明了该规则:
class ni:
bar = "hello"
def foo():
pi = ni()
def bar():
pi.bar = "eggs"
pi.bar = "spam"
print(pi.bar)
bar()
print(pi.bar)
ni.bar
>>> hello
foo()
>>> spam
>>> eggs
这与代码的简化版本之间的主要区别在于对名为hee
的变量的显式赋值。这里pi.bar
中的bar()
首先在pi
中查找bar()
对象。找不到它,它的范围开始缩小到foo()
,首先声明pi
对象。