0

I'm trying to build a GUI for a simple application with Tkinter on Python 3.3.0. I have stumbled upon a little programming quirk that at first sight it seems wrong. Although it isn't a problem per se (it isn't affecting my objective) it doesn't make sense in a Pythonic way.

So, here is the source:

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()

Running this and clicking the "Goodbye" button closes the window, as expected... however here resides the problem. If I run this simplified version of the code:

def foo():
    def bar():
        hee = "spam"
    hee = "eggs"
    print(hee)
    bar()
    print(hee)

foo()

>>> eggs
>>> eggs

I don't access the hee defined in foo() and create a new hee in bar(), as it should. If I were now to add nonlocal hee to the beginning of the bar() def, the output:

>>> eggs
>>> spam

Would be the expected one.

So, my question here is why I am able to call the root object in the first example without first declaring it nonlocal?

Doktoro Reichard
  • 577
  • 1
  • 7
  • 22
  • 1
    possible duplicate of [Short Description of Python Scoping Rules](http://stackoverflow.com/questions/291978/short-description-of-python-scoping-rules) – Eric Urban Aug 10 '13 at 23:40
  • 1
    @Eric Thanks. After reading it, I understood the problem. Since in the simplified code I explicitly **declared** a variable, where in the real example I accessed an attribute from a previously declared object, thus I was following the LEGB scope rule. Assuming I didn't declare another root object at `bar()` it should scope down to the one declared on `foo()`. – Doktoro Reichard Aug 11 '13 at 00:03

1 Answers1

0

As according to Short Description of Python Scoping Rules (see also The Python Tutorial) object name scope resolution goes according to the LEGB rule (Local, Enclosing functions, Globals, Built-ins).

That being said, the following example exemplifies the rule:

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

The main difference between this and the simplified version of the code is the explicit assignment of a variable named hee. Here the pi.bar in bar() looks for the pi object first in bar(). Not finding it, it begins to scope down to foo(), where the pi object is first declared.

Community
  • 1
  • 1
Doktoro Reichard
  • 577
  • 1
  • 7
  • 22