[Tutor] Fixing Globals

Dave Angel davea at davea.name
Sat Mar 16 20:52:07 CET 2013


On 03/16/2013 03:04 PM, kendy at kendy.org wrote:
> Dear Tutor
>
> Global constants and variables are bad.

First, let me define my own "rule."  Global constants should be all 
uppercase, and global variables should be avoided.  Trivial and buggy 
scripts may ignore both rules. A trivial script is typically anything 
under 30 lines.  Buggy scripts are those which you delete as soon as you 
ran them once.

So what's a global constant?  It's something that's set once, soon after 
the script starts, and *usually* not changed later in the run.  For 
example, cmdline arguments and things directly derived from them. 
Special numbers (such as math.pi which is global in that module, and 
should have been capitalized).  OS-specific details.

> But what's better? I've heard some
> suggestions, but haven't seen much actual code showing how to improve globals. I
> don't like:
>
> * Passing a lot of individual arguments.


I don't know how many you consider 'a lot.'  Consider factoring the 
function into simpler components.

> * Creating a structure with unrelated elements.

Presumably you mean a class instance with unrelated attributes.  And 
yes, certainly if you're creating a singleton class just as a holder for 
a pile of globals, then you might as well use the globals() collection 
in a given module. rather than writing your own.  On the other hand, 
things that are unrelated in one context may very well be related in 
another.  Smart dividing up of the problem is one of the things that 
helps makes code readable and reusable.

> * Passing a structure, as an argument, through a function that uses only one (or
> none of the) elements in the structure.

Here, I have to disagree entirely. If the class is intelligently 
designed, the instance is holding a bunch of interconnected data.  If 
the function needs one thing from it, no harm done passing the whole 
instance.

An example is a gui 'listbox' instance.  It has lots of data that the 
gui will use in painting it, positioning it, and generating events about 
it.  But an individual portion of the code may be only interested in the 
selected item in the list, not in the title, nor the horizontal size, 
nor ...

>
> I created an example (below), that could be written with global constants and
> variables. How would you suggest handling something like this? (I don't need you
> to stick to my example.)
>
> #!/usr/bin/python
>
> START = '<'
> END = '>'
>
> def getargs():
>      getops()
>      if
>          in_filename_1 =
>          in_filename_2 =
>          out_filename_1 =
>          out_filename_2 =
>          flag1 =
>          verbose =

Take a look at the modules in the standard library that do this sort of 
thing.  They return an object which contains all the parsed parameters.

>
> def this():
>      open_for_read()
>      stuff()

And if you decide to open two files instead of one, and process them 
both in a similar way?  Suddenly you'll need to pass a filename into 
this function.  Why not start that way, so the function is readable?

>
> def open_for_read(filename):
>      in_filehandle = open(
>      return in_filehandle

Looks good.
>
> def stuff():

   def  stuff(c, foo):

        """ interpret the character c and set the flag that will control 
how the rest of the program works
        """
>      if c == START or c == END:
>          foo_the_bar =
        if c in START+END:
            foo.BAR =
>
> def that():
>      things()
>      write_status(out_filename_1)

Why are these in one function, if they're unrelated?


The rest of the examples were too abstracted to be able to comment on.
>
> def things():
>      bar_the_foo = foo_the_bar
>      if verbose:
>          print(flag1)
>
> def write_status(out_filename_1):
>
> getargs()
> this()
> that()
>
>
> I very much appreciate the help that you have given me!
>
> Thanks
> Ken
>

When you start writing code that's big enough to have reusable pieces, 
you'll begin to appreciate how writing parameterized code makes it more 
reusable.  And when you try to debug stuff where a change in one 
function's use of a global breaks another function far away, you'll 
start to appreciate how it's handy to have each function have a 
(somewhat) reduced space it can damage, or be damaged by.

My biggest disasters were "trivial" programs that grew beyond their 
original scope, and I never changed the mindset in rewriting them.  I 
had once such program recently which had many authors and was a real 
mess.  (Besides, it was written in perl, which it makes it much easier 
to write unmaintainable hacks)  I wanted to make a substantial change 
and wound up writing a new program that invoked the first.  That first 
couldn't walk on my globals once it was in a separate process.


-- 
DaveA


More information about the Tutor mailing list