[Tutor] global

Jeff Shannon jeff@ccvcorp.com
Fri Aug 1 14:15:02 2003


Kirk Bailey wrote:

 > Jeff Shannon wrote:
 >
 >> Kirk Bailey wrote:
 >>
 >>> Got a script that wants to bark. Early in the program I
 >>> define some defaults for certain variables to define state
 >>> (they are used as boolian flags, 1/0 stuff). Later, a
 >>> function referrs o one- and barks. Says it does not know
 >>> the variable- undefined. Hmmm, sure it is... Apparently
 >>> this function is not aware the variable is already defined.
 >>> How do I force a variable to be global so it will
 >>> automatically be available to the insiode structure of a
 >>> defined function without having to formally pass it as an
 >>> arguement?
 >>
 >> Presuming that this is within the same module, nothing needs
 >> to be done. However, rebinding a name that [supposedly] points
 >> to a global object can result in a problem like what you
 >> mention [...]
 >
 > Jeff, to conserve bandwidth, I have created a link on the website
 > that will accurately display the current script.
 >
 > http://www.tinylist.org/wikinehesa.txt

Okay, it looks to me like I was more-or-less right about your
problem.  Here's the relevant parts of your script:


# Flags to control things
A=0    # Anchor toggle flag
B=0    # Bold toggle flag
I=0    # Italic toggle flag
U=0    # underscore toggle flag

def htmlize(thing,A,B,I,U):    # this converts wikicode to html, for one 
line.
[...]
        if exists(thing,"'''"):
            if B:
                thing=string.replace(thing,"'''","<B>")
            else:
                thing=string.replace(thing,"'''","</B>"
            B=not B    # toggle B flag
        # I am concerned that this won't toggle within a line, only between
[...]
index=0                    # index is a pointer for lines in a list.
for line in finalrawpage:        # each line will be treated in the page
    finalrawpage[index]=htmlize(line,A,B,I,U) # line by line, gibve it 
the treatment!
    index=index+1            # incrementing the counter to point the 
next line


So, you have a global variable B.  When htmlize() is called, that
variable is passed into the function as a parameter.  Once inside
the function, you're calling that parameter by the same name as
the global variable, but it is in fact a separate entity (even
though it holds the same value).  Thus, the line 'B = not B' toggles
the value of the local (parameter) variable, which now becomes 1,
but it does not affect the global variable.  Thus, on your next
trip through htmlize(), B is *still* 0.

I presume that adding these as parameters was an attempt to fix the
problem you originally mentioned, where a variable was reported as
being undefined.  That's what would have happened if you didn't pass
the flags in as parameters, i.e. your parameter list was just

def htmlize(thing):  [...]

In this case, when Python loads your code and compiles it to bytecode,
it notices the assignment to B ('B= not B') inside your function. 
Since you assign to this name, it's assumed to be a local variable,
and it's given a place in the fast-locals namespace.  Note that this
happens at load-time.  When you actually *run* the function, you
come to the statement 'if B:'.  At this point, Python tries to load
a value for B; it recognizes that it's got a space in fast-locals,
but then finds no value for it there because you haven't assigned
anything to it within the function.  (There's a global B, but Python
won't look for it because it "knows" that this is supposed to be a
local variable.)  That's when you get your UnboundLocalError.

You can prevent that error by stating, within htmlize(), that B (and
the other flags) are global --

def htmlize(thing):
    global A, B, I, U
    [...]

Now Python knows that these are intended to be globals, and it won't
reserve that space for them in fast-locals.  When it gets to the
previously problematic 'if B:', it will properly look up (and find)
B in the global namespace, and when you assign to B it will know to
change the value of the global name instead of creating a new local
name.  Personally, I'd lean towards using a class here, and having
htmlize() be a method of that class and your flags be attributes, but
that's a matter of personal taste -- I'm a big fan of using objects and
not so happy about globals.

Incidentally, you're right about your mentioned concern -- if you have
two or more sets of ''' on a single line, your function as is will
replace all of them with the same tag (either start or end), rather than
alternating tags.  In order to properly handle multiple tags on the
same line, you'll need to do something a bit more complicated.  One
possibility would be to split the line on ''', and then reassemble it
with alternation between <B> and </B>.  You'd need to keep track of
just how many instances of ''' there were, however, and be careful to
not have a spurious tag at the end of the reassembled line -- but you'd
also need to be sure that, if the old line ends with ''', you put the
proper tag on the end of the new line.  All of this is less trivial than
it seems at first glance, but it certainly can be done if given a bit
of careful thought.

Jeff Shannon
Technician/Programmer
Credit International