11

I found importing modules in Python complicated, so I'm doing experiments to clear it up. Here is my file structure:

PythonTest/
  package/
    __init__.py
    test.py

Content of __init__.py:

package = 'Variable package in __init__.py'
from package import test

Content of test.py:

from package import package
print package

When I stay out of package(in PythonTest), and execute python package/test.py, I get:

Traceback (most recent call last):
  File "package/test.py", line 1, in <module>
    from package import package
ImportError: No module named package

The expected output is Variable package in __init__.py. What am I doing wrong?


However, I can get the expected output in the interactive mode:

sunqingyaos-MacBook-Air:PythonTest sunqingyao$ python
Python 2.7.10 (default, Oct 23 2015, 19:19:21) 
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import package
Package in __init__.py
nalzok
  • 14,965
  • 21
  • 72
  • 139
  • It doesn't look like the module search path is set up for the `package` package to be findable. – user2357112 Aug 05 '16 at 06:34
  • @user2357112 So I should set `PYTHONPATH` or modify `sys.path`? But why everything is OK under the interactive mode? – nalzok Aug 05 '16 at 06:37
  • I'm assuming you are starting the interactive mode from the same directory as your file, so that path becomes part of the search path automatically. Try starting python from a totally different directory – WombatPM Aug 05 '16 at 06:51
  • The directory from which I invoked the interactive mode is exactly the directory from which I executed `python package/test.py`. When I enter a totally different directory, neither of this two approaches works. – nalzok Aug 05 '16 at 06:54
  • 1
    `python package/test.py` adds the directory of the script you're executing to the search path, not the directory you're launching the script from. – user2357112 Aug 05 '16 at 07:18
  • @user2357112 So to fix this, I should write another module in `PythonTest`, and invoke `test.py` from it? (Maybe simply calling a module in a package bypassing its package is a mistake?) – nalzok Aug 05 '16 at 07:21

1 Answers1

13

First Let's see how Python search for packages and modules. sys.path

A list of strings that specifies the search path for modules. Initialized from the environment variable PYTHONPATH, plus an installation-dependent default.

That's the search paths. Therefore, if your module/package is located in one of sys.path, python interpreter is able to find and import it. The doc says more:

As initialized upon program startup, the first item of this list, path[0], is the directory containing the script that was used to invoke the Python interpreter. If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input), path[0] is the empty string, which directs Python to search modules in the current directory first.

I modified test.py as an example.

import sys; import pprint
pprint.pprint(sys.path)

from package import package
print package 

There are two cases:

$ python package/test.py
['/Users/laike9m/Dev/Python/TestPython/package',
 '/usr/local/lib/python2.7/site-packages/doc2dash-2.1.0.dev0-py2.7.egg',
 '/usr/local/lib/python2.7/site-packages/zope.interface-4.1.3-py2.7-macosx-10.10-x86_64.egg',
 '/usr/local/lib/python2.7/site-packages/six-1.10.0-py2.7.egg',
 '/usr/local/lib/python2.7/site-packages/colorama-0.3.3-py2.7.egg',

As you see, path[0] is /Users/laike9m/Dev/Python/TestPython/package, which is the directory containing the script test.py that was used to invoke the Python interpreter.

$ python                                         
Python 2.7.12 (default, Jun 29 2016, 14:05:02)
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import package
['',
 '/usr/local/lib/python2.7/site-packages/doc2dash-2.1.0.dev0-py2.7.egg',
 '/usr/local/lib/python2.7/site-packages/zope.interface-4.1.3-py2.7-macosx-10.10-x86_64.egg',
 '/usr/local/lib/python2.7/site-packages/six-1.10.0-py2.7.egg',
 '/usr/local/lib/python2.7/site-packages/colorama-0.3.3-py2.7.egg',
...

Now comes the second case, when invoked interactively, "path[0] is the empty string, which directs Python to search modules in the current directory first." What's the current directory? /Users/laike9m/Dev/Python/TestPython/.(look this is the path on my machine, it's equivalent to the path to PythonTest in your case)

Now you know the answers:

  1. Why did python package/test.py give ImportError: No module named package?

    Because the interpreter does not "see" the package. For the interpreter to be aware of package package, PythonTest has to be in sys.path, but it's not.

  2. Why did this work in interactive mode?

    Because now PythonTest is in sys.path, so the interpreter is able to locate package package.

laike9m
  • 18,344
  • 20
  • 107
  • 140