Repository navigation
Behaviour of modules depends on how they where imported #65752
Description
Activity
I found a condition where different behaviour could be observed depending on how a module is imported.
It seems to be different to write:
import module # against: from package import module
In the attachment you find a minimal package (imptest) with this organization:
imptest
|-> __init__.py (empty)
|-> m.py (module which initializes a variable "foo=0")
|- sub (package)
|-> __init__.py (empty)
|-> subm.py (module which, upon import, changes "m.foo=1")And two scripts which can be directly executed:
|-> run0.py (using "import m")
|-> run1.py (using "from imptest import m")Contents of the module m:
#########################
foo=0
def do():
global foo
foo=1
print('doing foo=',foo)
print("imported foo=",foo)Contents of module subm:
#######################
from imptest import m
from imptest import m
print("imported sub, foo=",m.foo)Both run0.py and run1.py imports module m and calls the do() function, thus theoretically changing foo to 1.
Both later import the subm module, which in turn imports again the m module. What I would expect is that,
since m is already in memory, it is not really imported again: so foo remains equal to 1 also after subm import.I found that this actually depends on how I imported m in the script.
Contents of run0.py:
####################
import m
m.do()
print("importing subm")
from imptest.sub import submResult:
imported m; foo= 0
doing foo= 1
importing subm
imported m; foo= 0
imported sub, foo= 0As you can see from printout "importing subm", the m module is imported again and thus foo is reset to 0. In run1.py,
I changed the line "import m" to "from imptest import m", and got the expected behaviour:Contents of run1.py:
####################
from imptest import m
m.do()
print("importing subm")
from imptest.sub import submResult:
imported m; foo= 0
doing foo= 1
importing subm
imported sub, foo= 1I know that directly running a module in the first level of a package may seem strange or not correct, but could someone explain why this is happening?
I would expect a module to be loaded in memory at the first import and then referred in any way I later or elsewhere in the program choose to import it.- addedinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on May 22, 2014 Here's a simpler demo for what I believe you are experiencing:
$ mkdir package $ cd package/ $ touch __ini__.py module.py $ export PYTHONPATH=.. $ python3 Python 3.3.2+ (default, Feb 28 2014, 00:52:16) [GCC 4.8.1] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import module, package.module >>> module is package.module False
Even though module and package.module correspond to the same file
Python does not recognize that you intend the former to be part of a package. Your run0.py script goes through its sys.path entries and unfortunately the first entry points into a package so that all modules in that package become also visible as toplevel modules.A good way to avoid this trap is to use relative imports
>>> from . import module Traceback (most recent call last): File "<stdin>", line 1, in <module> SystemError: Parent module '' not loaded, cannot perform relative import
This is a consequence of a script's directory getting prepended to sys.path. See issue bpo-13475.
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields: