1

I have two modules: a.py and b.py

a.py:

foo = 0
def increase():
    global foo
    foo += 1

b.py:

from a import *
increase()
print(foo)

Run the b.py will get the result: 0, but my expect result is 1 Then I modified the b.py

b.py:

import a
a.increase()
print(a.foo)

Then I get the correct result: 1

My question is why the first edition of b.py getting a wrong result. What's the correct way to import a global variable?

Jruv
  • 1,438
  • 2
  • 9
  • 10
  • 1
    Please DO NOT USE `from bar import *`. It will lead you only to sadness, and ruin. I wish there weren't features in the language that were as obviously convenient and non-obviously a bad idea as this pattern, but that's how it is. The straightforward answer to your question, though, is that after the import there are two copies of the name `foo`, one in the original module and one in your module, pointing to `0`. `increase()` is closed over the first `foo` and rebinds that one to `1`, but the second `foo` stays bound to `0`. – Andrew Gorcester Aug 02 '14 at 05:16
  • @AndrewGorcester True, it's better to avoid using `from bar import *` but there are situations where it's more "practical" to use it cause it makes the code less verbose. Since we won't be able to preach (effectively) against using it, the least we can do is spread the word about [*__all__*](http://stackoverflow.com/questions/44834/can-someone-explain-all-in-python) and encourage its usage. – Nir Alfasi Aug 02 '14 at 05:54
  • @alfasin I wouldn't excuse `from bar import *` on those grounds; I would never ever let a use of it pass code review except in the case of libraries that are specifically made for it (I read once that there were scientific python environments that used the pattern in order to fundamentally transform the python experience, but I'm skeptical even in that case) – Andrew Gorcester Aug 02 '14 at 05:58
  • @AndrewGorcester that actually makes sense to me (scientific python envs): if your module is doing many calculations and in order to do that you need to `import matrix_operations` and `import mathematics` and then every other line of code looks like: `matrix = matrix_operations.transpose(matrix)` - again, to me this looks verbose and ugly and I would probably use "the forbidden" form. – Nir Alfasi Aug 02 '14 at 06:11
  • That said, I never had any problem with `import requests` or `import json` etc, not because the number of calls to functions from these modules is relatively low, but because it makes more sense to call `data = json.loads(payload.content)` than: `data = loads(payload.content)` since the latter form is confusing (it's not clear who loads what...) – Nir Alfasi Aug 02 '14 at 06:12
  • If you really want to do `data = foo(fizz)`, that's fine! Just explicitly import it with `from bar import foo`. It's the `*` that's disastrous, because now innocuous changes like adding a new function to a totally separate module can interfere with your module because the namespaces are not separate. Also because finding out what `foo()` actually does in your module is no longer a matter of checking the imports section of the module, but instead actually searching the contents of each imported module, which gravely harms readability. – Andrew Gorcester Aug 02 '14 at 06:25

1 Answers1

0

The correct way to import a global variable is to redesign your code so that you don't need to. You should import functions, and perhaps constants (conventionally UPPER_CASE in Python), but never global variables. Global variables are bad enough in libraries, but using them across multiple modules is just asking for trouble.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436