How is this variable sharing actually working in this package import?

Viewed 21

I'm struggling a bit to understand how this variable is able to be shared in this package setup I have. It is working fine using the standard config.py module, but I can't wrap my head around "why" it is working.

Here is my current simple package setup (code for each module is placed under the module for better readability here):

test/
    __init__.py
        from test import config
        config.username = "username-init"

    config.py
        username = "username-config"

    main.py
        from test import config
        print(config.username)  # prints "username-init"

In Python, when I run from test import main , here is what happens (learned by putting extra print() statements in each module to see what is happening):

  1. __init__.py runs first, which makes sense with the from test part of the import statement.
  2. __init__.py imports config.py
  3. config.py runs which sets the username variable to the initial value of username-config
  4. So at this point, __init__.py has the username variable in its global namespace.
  5. main.py finally runs, which once again runs from test import config
  6. main.py prints config.username which returns the edited value username-init

My question centers around step 5 above. By putting extra print() statements in each module, I can see that when main.py runs its from test import config line, __init__.py is not run a second time as it was the first time in Step 1 above. Why wouldn't main.py have to run __init__.py also since the main.py namespace would have no knowledge of anything in __init__.py ? Certainly my Python session's global namespace now has knowledge of __init__.py after Step 1 above, but the main.py module's namespace would not, so when main.py encounters its own from test import config line it would need to run __init__.py as was done in Step 1, correct?

1 Answers

A module is just executable code which typically involves creating useful objects and putting them in its namespace. If you executed the module’s code again every time it was imported, you would end up with multiple versions of every class (which wouldn’t work properly when used together) as well as of every bit of mutable state (which is even worse than having mutable global state in the first place). There are also cases where the runtime and memory usage would be exponential in the depth of the imports.

Of course Python doesn’t do this; sys.modules stores modules already imported and provides them for reuse by further importers.

Related