1

I just bumped into an unexpected (at least, for me!) behavior, and I'm trying to understand it. Let's say I have a main file:

main.py

from my_packages.module_00 import my_function

def main():
    my_function()

if __name__ == "__main__":
    main()

and, in the folder "my_packages", the module module_00 containing the function definition for "my_function" and a global variable:

module_00.py

global_var = 'global variable'


def my_function():
    print(f'Do I know {global_var}???')

When I run main.py, it outputs:

Do I know global variable???

And I'm trying to figure out why it's working.
I would expect the variable global_var to have a scope limited only to the module where it's defined (the answer to this question seems to confirm it). Basically, I assumed that importing my_function by

from my_packages.module_00 import my_function

was equivalent to copy/pasting the function definition in main.py. However, it seems that...the imported function somehow keeps track of the global variables declared in the module where the function itself has been defined?
Or am I missing something?

Carlo
  • 1,321
  • 12
  • 37
  • It would be easier to answer if you included actual code and actual output. The code you've provided has a syntax error; I assume you edited your real code but didn't try actually running it. Providing a useful answer would require rewriting the example in your question. – Samwise Mar 21 '22 at 19:56
  • 1
    Where is this `some value` you're referencing coming from? Did you mean `global variable`? Importing is not similar to copy-pasting, it's just making a reference to the function in the module available under a certain name inside main. – MatsLindh Mar 21 '22 at 19:57
  • 1
    Echoing Mats and putting it another way, `import` in Python is not at all the same as `#include` in C, even though its *purpose* is similar. – Samwise Mar 21 '22 at 19:59
  • 3
    Every function contains a reference to the global scope in which it is *defined*, and *that* is the scope where it looks up global variables, not the scope in which the function is *called*. – chepner Mar 21 '22 at 19:59
  • Sorry, I made a few changes because I thought it would make the example more readable, and I missed a couple of occurrences. Thanks for pointing them out! – Carlo Mar 21 '22 at 20:19
  • @Samwise, that's precisely the main reason of my confusion, coming from C/C++ I was expecting import in Python to behave in the same way. – Carlo Mar 21 '22 at 20:20

2 Answers2

3

However, it seems that...the imported function somehow keeps track of the global variables declared in the module where the function itself has been defined?

That's exactly what it is doing.

>>> from module_00 import my_func
>>> my_func.__globals__['global_var']
'global variable'
>>> module_00.global_var is my_func.__globals__['global_var']
True
>>> module_00.global_var = 3
>>> my_func.__globals__['global_var']
3

__globals__ is a reference to the global namespace of the module where my_func was defined.

chepner
  • 497,756
  • 71
  • 530
  • 681
2

Fix a couple of typos and your code works as expected. Each module in Python has its own private symbol table for the module's global variables.

  1. import in main.py must be my_func not my_function matching the function name as defined in module_00.py.
  2. ref in f-string in module_00.py must be {global_var} not {global variable}.

main.py

from my_packages.module_00 import my_func
                                  ^^^^^

def main():
    my_func() # my_func not my_function

if __name__ == "__main__":
    main()

module_00.py

global_var = 'global variable'

def my_func():
    print(f'Do I know {global_var}???')
                       ^^^^^^^^^^

Output:

Do I know global variable???

If you want to access a module's global variable then you can import the module and access the variable with the syntax: package.module_name.variable_name; e.g. my_packages.module_00.global_var

CodeMonkey
  • 22,825
  • 4
  • 35
  • 75
  • I'm sorry, I made a couple of changes to make it more readable and didn't fix everything correctly, thank you for poiting it out! – Carlo Mar 21 '22 at 20:18