homepage

This issue tracker has been migrated to GitHub , and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Behaviour of modules depends on how they where imported
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.2, Python 2.7
process
Status: closed Resolution: duplicate
Dependencies: Superseder: Add '--mainpath'/'--nomainpath' command line options to override sys.path[0] initialisation
View: 13475
Assigned To: Nosy List: brett.cannon, eric.snow, mythsmith, ncoghlan, peter.otten
Priority: normal Keywords:

Created on 2014年05月22日 15:37 by mythsmith, last changed 2022年04月11日 14:58 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
imptest.zip mythsmith, 2014年05月22日 15:37 imptest package exposing import inconsistencies
Messages (3)
msg218901 - (view) Author: mythsmith (mythsmith) Date: 2014年05月22日 15:37
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 subm
Result:
imported m; foo= 0
doing foo= 1
importing subm
imported m; foo= 0
imported sub, foo= 0
As 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 subm
Result:
imported m; foo= 0
doing foo= 1
importing subm
imported sub, foo= 1
I 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.
msg218903 - (view) Author: Peter Otten (peter.otten) * Date: 2014年05月22日 17:17
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
msg218905 - (view) Author: Eric Snow (eric.snow) * (Python committer) Date: 2014年05月22日 17:41
This is a consequence of a script's directory getting prepended to sys.path. See issue #13475.
History
Date User Action Args
2022年04月11日 14:58:03adminsetgithub: 65752
2014年05月23日 00:29:13berker.peksagsetsuperseder: Add '--mainpath'/'--nomainpath' command line options to override sys.path[0] initialisation
2014年05月22日 17:41:38eric.snowsetstatus: open -> closed
resolution: duplicate
messages: + msg218905

stage: resolved
2014年05月22日 17:17:26peter.ottensetnosy: + peter.otten
messages: + msg218903
2014年05月22日 15:44:32ezio.melottisetnosy: + brett.cannon, ncoghlan, eric.snow
2014年05月22日 15:37:33mythsmithcreate

AltStyle によって変換されたページ (->オリジナル) /