[Tutor] Accessing variables in main from functions in a module

Dave Angel davea at ieee.org
Sat Oct 31 05:02:08 CET 2009


Kent Johnson wrote:
> On Fri, Oct 30, 2009 at 6:39 PM, Robert Lummis <robert.lummis at gmail.com> wrote:
>   
>> I want to move some functions from my "main" program file to a module
>> file because the main file is getting too big for convenience. The
>> functions access arrays (lists of lists) that are defined and
>> initialised in the main file. How do I reference the main file arrays
>> from statements within the module file?
>>     
>
> A couple of solutions:
> - Put the arrays into some kind of structure that you can pass as an
> argument. The structure could be a list, dict or custom class.
> - Create a class (or possibly more than one class) to hold both the
> data and the functions that operate on it.
>
>   
>> With everything in the main file a function like the following works
>> as expected:
>>
>> def functionA (row, col, x):
>>     grid[row][col] =a value that depends on x and other values in grid>
>>
>> where grid[] is initialised outside of any functions (i.e. in the main).
>>
>> So how do I write that function when I move it to a module file? I
>>     
>
> That might make a good method of a grid class. Then it would become
> something like
> def functionA(self, row, col, x):
>   self.grid[row][col] =..
>
>   
>> So how do I write that function when I move it to a module file? I
>> thought I read somewhere that the main routine has the name "__main__"
>> so I tried:
>>
>>  __main__.grid[row][col] =...>
>>
>>  but that gives "NameError: name '__main__' is not defined".
>>     
>
> You can
>   import __main__
> and the above will work but that is *not* the best solution.
>
>   
>> I understand that it is best to minimize cross-file references but I
>> feel it is warranted in this case.
>>     
>
> Cross-file references are not bad by themselves but circular
> references (module A uses module B and B uses A) are a bad idea.
>
>   
>> Even if you think it isn't good
>> practice I would like to understand how to do it (or else why it can't
>> be done). Is there some other way to keep files from getting too big?
>>     
>
> Yes. Object-oriented design is the most common way of dealing with
> this. Think about decomposing your code into cooperating objects.
>
> Kent
>
>   
Listen to everything Kent tells you.  He knows more about Python than I 
probably ever will.  But I have been programming for a long time, and 
sometimes I have to be pragmatic on the way to becoming correct.  So 
take this next suggestion as a stop-gap while you debug some of these 
concepts.

Make a brand new module just to hold these global variables.  Call it   
constants.py

In that module, give your initial values for all these globals, but 
don't do anything else.  If absolutely necessary, make a single function 
in the module that'll be called at the very beginning of the script to 
do further initialization.  Above all, don't put any imports in this 
module, except for the obvious stdlib ones, such as os and sys.  But not 
to any other module of your own code.

Now, add an import of that module everywhere you need access to these, 
including from your script.  So if you need access to the constant grid, 
you reference it with    constants.grid

Now I deliberately called the module constants because good practice 
says you'd only use this approach for things which do not change while 
the program is running.  Things like flags passed in from the command 
line, or environmental things like the directory in which files are to 
be stored.

So if you followed my advice to call it constants.py, then you'd be 
reminded each time that this is a temporary hack.

Personally, I like the class approach, where related data is grouped 
together, so a single parameter can be added to each function.  And many 
times, this can lead to generalizations where you suddenly realize that 
instead of one grid, you need to operate on more than one, and the same 
functions could deal with either one. Passing grid (or a class object 
containing grid) would then be a fortunate choice.  And realize that 
object-orientation isn't an all-or-nothing approach.  Make objects out 
of those groups of things that you think there's ever going to be a 
chance of multiple usage, and leave the rest separate values.

And in addition to instance attributes, you can create methods, but you 
could start by doing just the lowest level ones.  For example if your 
grid is implemented as a list of lists, maybe you want accessor methods 
that give it a different appearance, like a single vector.  Or if there 
are two attributes that are interrelated, you can use methods to keep 
them in synch, instead of counting on everyone following the rules.

DaveA



More information about the Tutor mailing list