0

我正在尝试在 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定义的 infoo()并创建一个新hee的 in bar()。如果我现在要添加nonlocal heebar()def 的开头,输出:

>>> eggs
>>> spam

将是预期的。

所以,我的问题是为什么我能够root在第一个示例中调用该对象而不首先将其声明为非本地对象?

4

1 回答 1

0

根据Python 范围规则的简短描述(另请参见Python 教程)对象名称范围解析根据 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.barin首先在 in 中bar()查找pi对象bar()。没有找到它,它开始将范围缩小到第一次声明对象的foo()地方。pi

于 2013-08-11T20:58:21.640 回答