Python 3.3 - 函数内部的Tkinter对象访问

时间:2013-08-10 23:30:49

标签: python tkinter python-3.3

我正在尝试使用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对象而不首先声明它是非本地的?

1 个答案:

答案 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对象。