global variables and local functions.

Jonathan Hogg jonathan at onegoodidea.com
Thu Aug 29 10:49:33 CEST 2002


On 29/8/2002 5:11, in article T9hb9.114275$aA.26150 at sccrnsc02, "Micah Mayo"
<astrophels at yahoo.com> wrote:

> sourcePath = []
> destPath = []
> mlistLen = 0
> 
> populateLists():
>   textFile = open('movelist')
>   for eachLine in textFile.readlines():
>     source, dest = eachLine.split()
>     sourcePath.append(source)
>     destPath.append(dest)
>     mlistLen += 1
> 
> moveFiles():
>   for x in range(mlistLen):
>     shutil.copy2(sourcePath[x],destPath[x])
> 
> So, that's the part that doesn't work almost line for line.

Others have already pointed out that you are likely missing a 'global'
declaration somewhere. In general, when asking questions here you're most
likely to get a sensible reply if you can provide the exact failing code or
a trimmed, but still executable (and failing), version of it.

Basically this is so that others can try the code and see what's going
wrong. If we have to translate your pseudo-code to working code we may not
make the same mistake you did ;-)

>> There's a reason people eschew global variables, by the way.  <wink>
> Which is? I've been programming since Monday, so I'm pretty new at this. :)

The main problem with global variables is that they introduce hidden
dependencies between functions. Taking the 'populateLists' function in
isolation, it's not clear to a reader where 'sourcePath' and 'destPath' came
from, and where they are going. This makes your code harder to maintain, and
also harder to reuse in another situation. Unless your next program uses the
same global variables as this one, the 'populateLists' function will need to
be rewritten.

[Another side note is the problem of "magic" constants, which are constant
values embedded into the program that define its behaviour. In this case
you've put the name of the file that contains the paths straight into the
function as a constant. If you ever need to change the name of that file
you'll need to hunt through the code looking for where you used it.]

You should try to pass data into and out of functions as arguments and
return values. I'd have written your functions as:

>>> def getPaths( filename ):
...     sourcePaths = []
...     destPaths = []
...     for line in open( filename ):
...         source, dest = line.split()
...         sourcePaths.append( source )
...         destPaths.append( dest )
...     return sourcePaths, destPaths
... 
>>> def moveFiles( sourcePaths, destPaths ):
...     for source, dest in zip( sourcePaths, destPaths ):
...         shutil.copy2( source, dest )
... 
>>> 

and called them as:

>>> sources, dests = getPaths( 'test' )
>>> moveFiles( sources, dests )
>>> 

The important point here being that all the information needed by each
function is passed in as arguments and the useful information it generates
comes back out as return values. You can then hook functions together by
passing the results of one in as arguments to another.

I've used a couple of other tricks like file iteration ('for line in
open(...)') to skip the readlines call, and lockstep iteration ('for source,
dest in zip(...)') so I don't need to worry about the list lengths.

Hope that helps.

Jonathan




More information about the Python-list mailing list