Button command callback question -- Part 2

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Button command callback question -- Part 2

GKalman-2
Thanks for the replies for my earlier question. I should have stated my question in a better way.
My question is related to SCOPE!
For example:
#====================================
from Tkinter import *
#-------------------------------------------------
def doIt():
     print x
#------------------------------------------------
root=Tk()

btn=Button(root,text="DO",bg="cyan",command=doIt)
btn.pack(side=BOTTOM)

x=11
 

#NOTE that it works even when the mainloop() method below is commented out!!!!
#root.mainloop()
#===================================================================

so: if
(1) there is no mainloop()
(2) x=11 is declared in the MAIN part
(3) command=doIt() has no argument
(4) doIt() fn appears ahead of the x=11 statement

My Question is: why x=11 is within the scope of the doIt() callback fn?
Reply | Threaded
Open this post in threaded view
|

Re: Button command callback question -- Part 2

Michael Lange
Hi,

Thus spoketh GKalman <[hidden email]>
unto us on Mon, 18 Jul 2011 05:24:53 -0700 (PDT):

(...)  

>
> #NOTE that it works even when the mainloop() method below is commented
> out!!!!
> #root.mainloop()
> #===================================================================
>
> so: if
> (1) there is no mainloop()
> (2) x=11 is declared in the MAIN part
> (3) command=doIt() has no argument
> (4) doIt() fn appears ahead of the x=11 statement
>
> My Question is: why x=11 is within the scope of the doIt() callback fn?
>

Here when root.mainloop() is commented out, the call to
 $ python test.py
immediately returns ;) Of course you don't need to explicitely call
mainloop() when you run python in interactive mode from a terminal.

Besides this I cannot see anything surprising in the behavior of the
code example. When you define x=11 you add an object "x" to the global
namespace. When doIt() is called and the print x command is being
executed, the interpreter will first look if an object x is defined
within the function's namespace and then look within the global namespace
for such an object. Only when it cannot find such an object in any
available namespace an error will be raised.
Of course the contents of the function body are not evaluated before the
function is actually called. So it is not important if doIt is defined
before x , but only if x is already defined when doIt() is called.

Maybe it helps you understand what happens if you change your example a
little. If you change the doit() definition like

 def doIt():
     x = 2
     print x

it will print 2 instead of 11 . It is important to understand that the
"outer" x will not be changed by calls to this function as you can verify
by e.g. adding a second button that will call the original version of
your doIt() function, or by changing it a little  more:

def doIt():
     print x
     def foo():
         x=2
         print x
     foo()

Now it will print first 11, then 2 , but without overriding the "outer" x,
as you can see by repeatedly pressing the button.

If you want to change the "outer" (=global) x , you need to add the
"global" statement:

def doIt():
     print x
     def foo():
         global x
         x+=1
         print x
     foo()

I hope this helps

Michael


.-.. .. ...- .   .-.. --- -. --.   .- -. -..   .--. .-. --- ... .--. . .-.

Death.  Destruction.  Disease.  Horror.  That's what war is all about.
That's what makes it a thing to be avoided.
                -- Kirk, "A Taste of Armageddon", stardate 3193.0
_______________________________________________
Tkinter-discuss mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/tkinter-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Button command callback question -- Part 2

Lion Kimbro-2

  I would also add a caution:

  If you assign x *anywhere* within the function, a prior use will fail...

  def foo():
      print x    # raises UnboundLocalError,
      x = 10   # ...because the interpreter knows that x is local.

  Only unassigned values are searched for in the global namespace, if not locally declared.

  I think the reason it's like this, is to keep variables in one function in one scope,
  for sanity's sake.


On Mon, Jul 18, 2011 at 11:21 AM, Michael Lange <[hidden email]> wrote:
Hi,

Thus spoketh GKalman <[hidden email]>
unto us on Mon, 18 Jul 2011 05:24:53 -0700 (PDT):

(...)
>
> #NOTE that it works even when the mainloop() method below is commented
> out!!!!
> #root.mainloop()
> #===================================================================
>
> so: if
> (1) there is no mainloop()
> (2) x=11 is declared in the MAIN part
> (3) command=doIt() has no argument
> (4) doIt() fn appears ahead of the x=11 statement
>
> My Question is: why x=11 is within the scope of the doIt() callback fn?
>

Here when root.mainloop() is commented out, the call to
 $ python test.py
immediately returns ;) Of course you don't need to explicitely call
mainloop() when you run python in interactive mode from a terminal.

Besides this I cannot see anything surprising in the behavior of the
code example. When you define x=11 you add an object "x" to the global
namespace. When doIt() is called and the print x command is being
executed, the interpreter will first look if an object x is defined
within the function's namespace and then look within the global namespace
for such an object. Only when it cannot find such an object in any
available namespace an error will be raised.
Of course the contents of the function body are not evaluated before the
function is actually called. So it is not important if doIt is defined
before x , but only if x is already defined when doIt() is called.

Maybe it helps you understand what happens if you change your example a
little. If you change the doit() definition like

 def doIt():
    x = 2
    print x

it will print 2 instead of 11 . It is important to understand that the
"outer" x will not be changed by calls to this function as you can verify
by e.g. adding a second button that will call the original version of
your doIt() function, or by changing it a little  more:

def doIt():
    print x
    def foo():
        x=2
        print x
    foo()

Now it will print first 11, then 2 , but without overriding the "outer" x,
as you can see by repeatedly pressing the button.

If you want to change the "outer" (=global) x , you need to add the
"global" statement:

def doIt():
    print x
    def foo():
        global x
        x+=1
        print x
    foo()

I hope this helps

Michael


.-.. .. ...- .   .-.. --- -. --.   .- -. -..   .--. .-. --- ... .--. . .-.

Death.  Destruction.  Disease.  Horror.  That's what war is all about.
That's what makes it a thing to be avoided.
               -- Kirk, "A Taste of Armageddon", stardate 3193.0
_______________________________________________
Tkinter-discuss mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/tkinter-discuss


_______________________________________________
Tkinter-discuss mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/tkinter-discuss