Mindboggling Scope Issue

James Stroud jstroud at mbi.ucla.edu
Mon Oct 25 01:16:14 CEST 2004


Hello All,

Please bare with me as I have seldom asked for help with my code, so I may do 
things a little wrong at times. If I ask in the wrong way, please by friendly 
like Tarry Reedy and suggest how I may better ask my questions.

So I will retry this one from the top, and with Tarry's suggestions 
incorporated. 

First I'll begin with a simple example that works from the python CLI:

% python
Python 2.3.3 (#2, Feb 17 2004, 11:45:40)
[GCC 3.3.2 (Mandrake Linux 10.0 3.3.2-6mdk)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> def outer():
...   def inner():
...     print bob
...   bob = "wuzzup?"
...   inner()
...
>>> outer()
wuzzup?

This is an experiment to prove that a function can "de-reference" a name even 
if the function is defined in a position of the code that preceeds said 
name's assignment in the enclosing scope. (Hopefully my vocabulary makes 
sense here--I am not a computer scientist). Please look at the code to see 
what I mean. Here, we are talking about the name "bob".

Second I present below two alternatives (designated "method1" and "method2" in 
the comments of the listings below) to a method that resides in a program I 
am writing. I run the program with the same python executable with which I 
generated the above example. These method listings are long but differ only 
where I have indicated in the comments. I am including them in their entirety 
so that I don't leave something critical out that I, as a relative novice, am 
missing.

With "method1" I get no error and the "ok()" method works as I expect and in 
accord with the example above. With "method2" I call "ok()", and when it 
prints to stdout I get the following error (after compile, when the program 
is being run):

Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python2.3/lib-tk/Tkinter.py", line 1345, in __call__
    return self.func(*args)
  File "./passerby", line 1378, in ok
    print result
UnboundLocalError: local variable 'result' referenced before assignment

So my question is, what is special about what I am doing here? Why does it not 
work like the first example I gave with the name bob? Have I found a bug in 
python? I should note that "passWindow" is not defined anywhere else but this 
method. Also, I should note that "method1" represents a 
workaround/alternative, so my program runs just fine. I just want to know 
what is going on here to imporve my own understanding. I think if anyone can 
give me a satisfactory answer on this one, we should all call them a "real 
expert".

Here are the listings I referred to above:

-----

    # method1 : works!
    def ask_for_password(self, message):
      def cancel():
        passWindow.destroy()
      def ok():
        # different : WORKS FINE!
        print passWindow.result
        pw = passEntry.get()
        if len(pw):
          # different
          passWindow.result = pw
        passWindow.destroy()
      message = "\n" + message + "\n"
      passWindow = Toplevel(self.get_mainWindow())
      # different : notice that passWindow is defined for the
      #                 first time in this whole program in the line above
      #                 It is not part of a larger scope!
      passWindow.result = None
      passWindow.title("passerby - Password Entry")
      self.get_mainWindow().deiconify()
      passWindow.transient(self.get_mainWindow())
      passWindow.geometry("400x180+50+50")
      passWindow.resizable(0,0)
      passLabel = Label(passWindow, text=message)
      passEntry = Entry(passWindow)
      passEntry.configure(width=48)
      passEntry.config(show="*")
      passEntry.bind("<Return>",ok)
      cancelButton = Button(passWindow, text="Cancel", command=cancel)
      okButton = Button(passWindow, text="OK", command=ok)
      passLabel.pack()
      passEntry.pack()
      cancelButton.pack()
      okButton.pack()
      passEntry.focus_set()
      passWindow.grab_set()
      self.get_tk().wait_window(passWindow)
      # different
      return passWindow.result

-----

    # method2 : doesn't work!
    def ask_for_password(self, message):
      def cancel():
        passWindow.destroy()
      def ok():
        # different : GETS ERROR!
        print result
        pw = passEntry.get()
        if len(pw):
          passWindow.result = pw
        passWindow.destroy()
      message = "\n" + message + "\n"
      passWindow = Toplevel(self.get_mainWindow())
      # different : notice that passWindow is defined for the
      #                 first time in this whole program in the line above
      #                 It is not part of a larger scope!
      result = None
      passWindow.title("passerby - Password Entry")
      self.get_mainWindow().deiconify()
      passWindow.transient(self.get_mainWindow())
      passWindow.geometry("400x180+50+50")
      passWindow.resizable(0,0)
      passLabel = Label(passWindow, text=message)
      passEntry = Entry(passWindow)
      passEntry.configure(width=48)
      passEntry.config(show="*")
      passEntry.bind("<Return>",ok)
      cancelButton = Button(passWindow, text="Cancel", command=cancel)
      okButton = Button(passWindow, text="OK", command=ok)
      passLabel.pack()
      passEntry.pack()
      cancelButton.pack()
      okButton.pack()
      passEntry.focus_set()
      passWindow.grab_set()
      self.get_tk().wait_window(passWindow)
      # different
      return result



-- 
James Stroud, Ph.D.
UCLA-DOE Institute for Genomics and Proteomics
611 Charles E. Young Dr. S.
MBI 205, UCLA 951570
Los Angeles CA 90095-1570
http://www.jamesstroud.com/



More information about the Python-list mailing list