Global variables in imported class functions in Python
global-variables, python, python-2.7
Solution
If you just want to know why it's not working:
First, `main` isn't setting a global `a`, but a local one. If you want to make it global, you have to be explicit:
def main():
global a
a = 1
# ...
But this won't fix the problem, because "global" in Python is per-module. In other words, that just creates a `foo.a`, but your code in `bar.Bar` will be looking for `bar.a`, which will not exist.
You could `import foo` and then access `foo.a` if you wanted. (In this case, the circular dependency shouldn't be a problem, and the `if __name__ == '__main__'` won't get executed twice.) Or you could assume that `foo` has been imported, and use `sys.modules['foo'].a`. Or you could inject `a` into `bar`'s dictionary from `foo`. Or lots of other tricks. But these are all horrible things to do.
If you can't make a global work, the right answer is almost always to not use a global. (In fact, even when you can make a global work, that's usually the right answer.)
So, how do you do that? Without knowing more about the details, it's hard to guess whether `a` belongs as an explicit module global, a class attribute, an instance attribute, a parameter to `incr`, etc. But figure out which one makes the most sense given what `a` represents, and do that.
In the comments, you suggested that you have a bunch of these configuration variables. If you wrap them all up in a `dict` and pass that `dict` to each object's constructor, that will make things simpler.
More importantly, a `dict` is a reference to a mutable object. Copying it just makes another reference to that same object.
main.py:
def main():
configs = {}
configs['gravity'] = 1.0
rock = rps.Rock(configs)
rock.do_stuff()
configs['gravity'] = 2.1
rock.do_stuff()
if __name__ == '__main__':
main()
rps.py:
class Rock(object):
def __init__(self, configs):
self.configs = configs
def do_stuff(self):
print('Falling with gravity {}.'.format(self.configs['gravity']))
When you run this, it'll print something like:
Falling with gravity 1.0.
Falling with gravity 2.1.
You haven't modified the value `configs['gravity']` (that's an immutable float; you can't modify it), but you have replaced it with a different value (because `configs` is a mutable `dict`; you can modify it just fine). You can try printing out things like `id(self.configs)`, `id(self.configs['gravity'])`, etc. in various places if the identity isn't clear.
Problem
I'm trying to spread my code across separate files to improve readability, and I'm running in to trouble with undefined global names being referenced inside imported files. Is there a better solution than deliberately passing all necessary values to the functions when called? My code currently is like this: ``` #foo.py import bar def main(): a = 1 b = bar.Bar() while True: a += 1 b.incr() print a print b.c if __name__ == '__main__': main() #END foo.py ``` ``` #bar.py class Bar: def __init__(self): self.c = 0 def incr(self): self.c += a #END bar.py ``` It gives me NameError: global name 'a' is not defined. Do I need to rewrite main() like this: ``` def main(): b = new bar.Bar() while True: a += 1 b.incr(a) print a print b.c ``` And rewrite incr() like this: ``` def incr(self,a): c += a ``` Or is there a better way? For the record, the above code is heavily abstracted. The actual code involves a great many classes and functions passing many variables of several types, including some large dictionaries. Thanks in advance!