[Tutor] inter-module global variable

Dave Angel davea at ieee.org
Sun Mar 28 13:01:14 CEST 2010


spir # wrote:
> Hello,
>
> I have a main module importing other modules and defining a top-level variable, call it 'w' [1]. I naively thought that the code from an imported module, when called from main, would know about w, but I have name errors. The initial trial looks as follows (this is just a sketch, the original is too big and complicated):
>
> # imported "code" module
> __all__ ="NameLookup", "Literal", "Assignment", ...]
>
> # main module
> from parser import parser
> from code import *
> from scope import Scope, World
> w = World()
>
> This pattern failed as said above. So, I tried to "export" w:
>
> # imported "code" module
> __all__ ="NameLookup", "Literal", "Assignment", ...]
>
> # main module
> from parser import parser
> from scope import Scope, World
> w = World()
> import code		#    new
> code.w = w		### "export"
> from code import *
>
> And this works. I had the impression that the alteration of the "code" module object would not propagate to objects imported from "code". But it works. But I find this terribly unclear, fragile, and dangerous, for any reason. (I find this "dark", in fact ;-)
> Would someone try to explain what actually happens in such case?
> Also, why is a global variable not actually global, but in fact only "locally" global (at the module level)?
> It's the first time I meet such an issue. What's wrong in my design to raise such a problem, if any?
>
> My view is a follow: From the transparency point of view (like for function transparency), the classes in "code" should _receive_ as general parameter a pointer to 'w', before they do anything. In other words, the whole "code" module is like a python code chunk parameterized with w. If it would be a program, it would get w as command-line parameter, or from the user, or from a config file.
> Then, all instanciations should be done using this pointer to w. Meaning, as a consequence, all code objects should hold a reference to 'w'. This could be made as follows:
>
> # main module
> import code
> code.Code.w =
> from code import *
>
> # "code" module
> class Code(object):
>     w =None	### to be exported from importing module
>     def __init__(self, w=Code.w):
>         # the param allows having a different w eg for testing
>         self.w =
> # for each kind of code things
> class CodeThing(Code):
>     def __init__(self, args):
>         Code.__init__(self)
>         ... use args ...
>    def do(self, args):
>        ... use args and self.w ...
>
> But the '###' line looks like  an ugly trick to me. (Not the fact that it's a class attribute; as a contrary, I often use them eg for config, and find them a nice tool for clarity.) The issue is that Code.w has to be exported.
> Also, this scheme is heavy (all these pointers in every living object.) Actually, code objects could read Code.w directly but this does not change much (and I lose transparency).
> It's hard for me to be lucid on this topic. Is there a pythonic way?
>
>
> Denis
>
> [1] The app is a kind of interpreter for a custom language. Imported modules define classes for  objects representing elements of code (literal, assignment, ...). Such objects are instanciated from parse tree nodes (conceptually, they *are* code nodes). 'w' is a kind of global scope -- say the state of the running program. Indeed, most code objects need to read/write in w.
> Any comments on this model welcome. I have few knowledge on implementation of languages.
> ________________________________
>
> vit esse estrany ☣
>
> spir.wikidot.com
>
>   
The word 'global' is indeed unfortunate for those coming to python from 
other languages. In Python, it does just mean global to a single module. 
If code in other modules needs to access your 'global variable' they 
need normally need it to be passed to them.

If you really need a program-global value, then create a new module just 
for the purpose, and define it there. Your main program can initialize 
it, other modules can access it in the usual way, and everybody's happy. 
In general, you want import and initialization to happen in a 
non-recursive way. So an imported module should not look back at you for 
values. If you want it to know about a value, pass it, or assign it for 
them.

But Python does not have pointers. And you're using pointer terminology. 
Without specifying the type of w, you give us no clue whether you're 
setting yourself up for failure. For example, the first time somebody 
does a w= newvalue they have broken the connection with other module's w 
variable. If the object is mutable (such as a list), and somebody 
changes it by using w.append() or w[4] = newvalue, then no problem.

You have defined a class attribute w, and an instance attribute w, and a 
module variable w in your main script. Do these values all want to stay 
in synch as you change values? Or is it a constant that's just set up 
once? Or some combination, where existing objects want the original 
value, but new ones created after you change it will themselves get the 
value at the time of creation? You can get any of these behaviors, but 
only if you know which one you want, and code for it. There's no single 
answer, without guessing your intent.

If it's a single value that everyone should see the current value of, 
then put it in its own module, and have everyone access it explicitly, 
every time. Don't make an instance attribute or a class attribute. Just 
make a module called globals (or something) and say globals.w

By the way, your first "export" was a hack, where you fake a global 
variable in another module. But the second one, where you set a class 
attribute's value, is perfectly reasonable.

And also by the way, once you decide your real desired behavior, there 
still may be some syntactic sugar that's useful. For example, you might 
define a method (untested)

class Code(object):
....
@property
def w:
return globals.w

This way every instance appears to have such an instance variable, but 
it in fact always referring to the single global defined in globals.py

HTH
DaveA



More information about the Tutor mailing list