Mindboggling Scope Issue

James Stroud jstroud at mbi.ucla.edu
Sun Oct 24 16:46:12 EDT 2004


Hello All,

I originally posted this to the help list, but I wanted to try a broader 
audience. Its so bizarre, that it may take some discourse to understand what 
is going on.

Far below are two alternative methods I have made inside a class. In "method1" 
I create a name called "passWindow.result" and use it in the "ok()" function. 
In "method2", I simply call this name "result".

Matt Cowles gave this explanation:
> The important difference is that you assign to the variable result
> later in the function. If a variable isn't assigned to in a function,
> Python looks for it in enclosing namespaces:

If I understand Matt's answer, "ask_for_password(self,message)", should be the 
enclosing namespace for "ok()".  So I am still confused: notice how I defined 
"passWindow" on the line preceding the "result=None" (method2) or 
"passWindow.result=None" (method1) statments. I haven't defined "passWindow" 
before I defined it in the "get_password(self)" method, i.e. "passWindow", 
like "result" and "passWindow.result", is not part of the global name space 
or any other enclosing namespace beyond the "get_password(self)" method.

Testing Matt's explanation, I began a fresh CLI session (using the same python 
executable used for my program). The session is cut and pasted from my 
terminal:

% 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 works as I expect and in accord with Matt's explanation and the Laws of 
Common Sense, but it appears to be entirely inconsistent with the behavior of 
"method2" below. Thus, I am completely bewildered.

I have pasted the methods below (sorry they are so long, but I didn't want 
to alter them--maybe clues lie within).

-----

    # method1
    #####################################################################
    # get_password(self)
    #####################################################################
    def ask_for_password(self, message):
      def cancel():
        passWindow.destroy()
      def ok():
        # WORKS FINE!
        print passWindow.result
        pw = passEntry.get()
        if len(pw):
          passWindow.result = pw
        passWindow.destroy()
      message = "\n" + message + "\n"
      # make a new top level for the pass window
      passWindow = Toplevel(self.get_mainWindow())
      passWindow.result = None
      # title it something meaningful
      passWindow.title("passerby - Password Entry")
      # - will use the main view (view #0) to own the password entry
      #   this will help the user remember what he's doing
      # - need to show the main view
      self.get_mainWindow().deiconify()
      # - set ownership of the passWindow to main view
      passWindow.transient(self.get_mainWindow())
      # setting the geometry of the passWindow
      # pass_x = anEvent.x_root - 50
      # pass_y = anEvent.y_root - 50
      passWindow.geometry("400x180+50+50")
      # - don't let user change our beautiful window
      passWindow.resizable(0,0)
      # the entry label and field
      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)
      return passWindow.result

-----

    # method2
    #####################################################################
    # get_password(self)
    #####################################################################
    def ask_for_password(self, message):
      def cancel():
        passWindow.destroy()
      def ok():
        # GETS ERROR!
        print result
        pw = passEntry.get()
        if len(pw):
          passWindow.result = pw
        passWindow.destroy()
      message = "\n" + message + "\n"
      # make a new top level for the pass window
      passWindow = Toplevel(self.get_mainWindow())
      result = None
      # title it something meaningful
      passWindow.title("passerby - Password Entry")
      # - will use the main view (view #0) to own the password entry
      #   this will help the user remember what he's doing
      # - need to show the main view
      self.get_mainWindow().deiconify()
      # - set ownership of the passWindow to main view
      passWindow.transient(self.get_mainWindow())
      # setting the geometry of the passWindow
      # pass_x = anEvent.x_root - 50
      # pass_y = anEvent.y_root - 50
      passWindow.geometry("400x180+50+50")
      # - don't let user change our beautiful window
      passWindow.resizable(0,0)
      # the entry label and field
      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)
      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