Why do I have to use "global" so much when using Turtle?

J

John Ladasky

Hi, folks,

Some of you may remember that I am teaching some high school students how to program. Because they all love graphics, I have been investigating the turtle module, which I gather is built on top of Tk. I can see that real-time applications are possible. I'm writing a classic "bouncing-balls" program to demonstrate to my students.

In the main program code, I instantiate a turtle.Screen, named sc.

I draw a bounding box, whose size is described by the variables edgew and edgeh. I have a list of Turtle objects, which I named balls. I have a timer interval stored in tick.

In the main loop of my program, I bind a function to update the positions of the balls to a timer, thus:

sc.ontimer(move_balls, tick)

Inside my move_balls function, I could not get ANYTHING done without the following declaration:

global balls, edgew, edgeh, tick

For a while, I had a "quit" function that I bound to the q key:

sc.onkeypress(quit, "q")

The quit function simply printed a message, and then called sc.bye(). As with move_balls, quit wouldn't work unless I had a "global sc" declaration in it. (My shortened program skips my function and just binds sc.bye to theq key, avoiding the need for globals.)

Once I use globals, everything works fine. However, I haven't taught my students a thing about the globals declaration. Furthermore, I was always taught that the need for global variables generally indicated that YOU were writing a SLOPPY program!

However, neither Screen.ontimer() not Screen.onkeypress() appear to give mea way to pass arguments to functions of my own. Why don't they? Is this some limitation of Tk? I have worked with other GUI's before, and I don't remember having to jump through this particular hoop.

I'm torn between proceeding with turtle, burdening my students with comprehending globals (they're young, they just barely grasp the idea of namespaces) -- or, abandoning turtle for another approach.

Comments appreciated!
 
P

Peter Otten

John said:
Hi, folks,

Some of you may remember that I am teaching some high school students how
to program. Because they all love graphics, I have been investigating the
turtle module, which I gather is built on top of Tk. I can see that
real-time applications are possible. I'm writing a classic
"bouncing-balls" program to demonstrate to my students.

In the main program code, I instantiate a turtle.Screen, named sc.

I draw a bounding box, whose size is described by the variables edgew and
edgeh. I have a list of Turtle objects, which I named balls. I have a
timer interval stored in tick.

In the main loop of my program, I bind a function to update the positions
of the balls to a timer, thus:

sc.ontimer(move_balls, tick)

Inside my move_balls function, I could not get ANYTHING done without the
following declaration:

global balls, edgew, edgeh, tick

That's not limited to turtle, Python in general forces you to make shared
state explicit.

Simple alternatives to global would be a degenerate class

class state:
pass

or a magic import

import __main__ as state

With both of these (pseudo-)globals can be set with

state.some_global = some_value

However, most of the names you list above look like their values need not be
altered from within the function and thus the name not be declared global
anyway. To be sure you'd have to show us the code...
 
S

Steven D'Aprano

Hi, folks,

Some of you may remember that I am teaching some high school students
how to program. Because they all love graphics, I have been
investigating the turtle module, which I gather is built on top of Tk.
I can see that real-time applications are possible. I'm writing a
classic "bouncing-balls" program to demonstrate to my students.

In the main program code, I instantiate a turtle.Screen, named sc.

I draw a bounding box, whose size is described by the variables edgew
and edgeh. I have a list of Turtle objects, which I named balls. I
have a timer interval stored in tick.

In the main loop of my program, I bind a function to update the
positions of the balls to a timer, thus:

sc.ontimer(move_balls, tick)

Inside my move_balls function, I could not get ANYTHING done without the
following declaration:

global balls, edgew, edgeh, tick

That doesn't sound right. You don't need to declare globals unless you
are rebinding them (assigning to the name). So if you do something like
this:

def move_balls():
for ball in balls:
do_something_with(ball)


you're not assigning to global "balls" so no global declaration is
needed. But if you do this:


def move_balls():
balls = sorted(balls) # say
for ball in balls:
do_something_with(ball)


then you need a global declaration since you're assigning to the global
variable. Likewise for tick, edgew and edgeh -- if you're just *reading*
their value, you don't need to declare them.

For a while, I had a "quit" function that I bound to the q key:

sc.onkeypress(quit, "q")

The quit function simply printed a message, and then called sc.bye().
As with move_balls, quit wouldn't work unless I had a "global sc"
declaration in it.

Again, that sounds wrong. This should work, since sc is not assigned to:

def quit():
print("Bye now!")
sc.bye()


If that's not the case, there's something you're not telling us about
your code. Actual working examples are appreciated.
 
N

Ned Batchelder

For a while, I had a "quit" function that I bound to the q key:

sc.onkeypress(quit, "q")

The quit function simply printed a message, and then called sc.bye(). As with move_balls, quit wouldn't work unless I had a "global sc" declaration in it. (My shortened program skips my function and just binds sc.bye to the q key, avoiding the need for globals.)

It sounds like you didn't need as many global statements as you think.
In particular, you only need to use "global" if you are assigning to a
global name within a function. The quit function you describe didn't
have a "sc = ..." statement in it, and so should not have needed a
"global sc" statement.

Can you show the code with the global statements? There's very likely a
way to get rid of some of them.

--Ned.
 
N

Nobody

However, neither Screen.ontimer() not Screen.onkeypress() appear to give
me a way to pass arguments to functions of my own. Why don't they? Is
this some limitation of Tk? I have worked with other GUI's before, and I
don't remember having to jump through this particular hoop.

The usual approach in Python is to pass a bound method of an object, and
keep all of the data on that object.
 
J

John Ladasky

All right, never mind!

I hacked around this morning, making some changes to parts of my program that I thought were unrelated to my namespace issues. I was paring it down to a minimal example, to post here as Ned requested. As an experiment, I also commented out the global declaration line in move_balls... and everything worked this time.

I'm baffled as to what necessitated the global declaration in the first place. But since the goal was to teach my students a graphical tool, I don't think that I will investigate this matter any further.
 
R

rusi

All right, never mind!


I hacked around this morning, making some changes to parts of my program that
I thought were unrelated to my namespace issues. I was paring it down to a
minimal example, to post here as Ned requested. As an experiment, I also
commented out the global declaration line in move_balls... and everything
worked this time.


I'm baffled as to what necessitated the global declaration in the first
place. But since the goal was to teach my students a graphical tool, I don't
think that I will investigate this matter any further.

Not related to your question but to turtle graphics
Have you seen this?
http://code.google.com/p/pynguin/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top