[Tutor] Fixing Globals

Alan Gauld alan.gauld at btinternet.com
Sun Mar 17 00:07:31 CET 2013


On 16/03/13 19:04, kendy at kendy.org wrote:

> Global constants and variables are bad.

Really? Do you know why?
If you understand why then the measures to avoid them
become more palatable - the lesser of 2 evils.

Read-only globals are much less of a problem than read/write ones.
And in Python we limit the damage by restricting globals to a single 
module's scope. class variables do a similar job in OOP.

> * Passing a lot of individual arguments.

What's a lot? 30 or 40 is too many (and I've seen it done!).
But usually those 30 or 40 can be factored down to a few groups which 
can be put in records(objects or dictionaries etc). Less than 10 is 
probably OK.

If you find yourself looking at lots of globals then you need to step 
back and look at the overall structure of the code - the coupling 
between your functions and the data model. There is a school of thought 
that says you should design your data structures first and make the 
functions follow the structure of the data. That approach eliminates 
many of the problems people have with globals which are often caused by 
adding them ad-hoc as they are 'discovered' during coding.

> * Creating a structure with unrelated elements.

That's usually a bad idea but not necessarily terrible especially if 
it's a dictionary or object or similar 'named attribute' packaging tool.


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

That may be OK too, provided the functions below that
one use the elements.

There is a natural dependency tree there so passing in the
package of required data into the top level is not necessarily
bad if it preserves the cohesion of the function group.
If that is the case the group of functions probably
belong in a class and the data can either be instance
or class attributes.

> I created an example (below), that could be written with global constants and
> variables. How would you suggest handling something like this?

> #!/usr/bin/python
>
> START = '<'
> END = '>'

Well these appear to be the only explicit globals and as read only 
contstants they are OKish. They could also be moved into a separate 
module which you import.

> def getargs():
>      getops()

This is a good example why globals are bad. What does getops do? What 
has changed as a result of calling it? It doesn't return anything so all 
impact on the program is invisible and unpredictable.

ops = getops()  # ops could be a dictionary populated by getops

is more manageable and allows for multiple instances to exist

>      if
>          in_filename_1 =
>          in_filename_2 =
>          out_filename_1 =
>          out_filename_2 =
>          flag1 =
>          verbose =

Not sure what the 'if' is doing, I assume you imply that the assignments 
are all from global values? If so its better to pass the filenames in or 
read them from a config file or somesuch. Makes the code more flexible 
and reusable. Or they could all be in the ops dictionary we created above?

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

again by relying on a global side-effect in open... you limit this 
function to only being used with one file. And if used in any other 
program you need to ensure you create a global in it that has the exact 
same name - and hope nobody else already used it...

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

This is much better but notice above you don't pass the filename in and 
you don't assign the returned filehandle...

> def stuff():
>      if c == START or c == END:
>          foo_the_bar =

Potentially OK but you don't pass anything back. That implies foo... is 
changing global values, again bad for all the usual reasons. Better to 
capture the changes and pass them back. Or at least give an indication 
if the changes worked!

> def that():
>      things()
>      write_status(out_filename_1)

same as above. If the file were part of an object the status would be 
part of that same object and we could access it that way. You don't 
mention OOP but OOP is one of the biggest and best tools we have in 
removing globals.

Nothing new to add for the other code samples.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/



More information about the Tutor mailing list