Say my project is structured like this:
myproject
├── calendar.py
├── foo.py
└── __init__.py
In foo.py, I have
from calendar import isleap
I thought in Python 3.x, without using the explicit .calendar the code above should load the build-in calendar module instead my own calendar module, but apparently my local calendar.py is still being imported and it throws an error because there's no 'isleap' in mypkg/calendar.py. Why was my local calendar module imported here?
I had to rename calendar.py to cal.py to get this work..
from __future__ import absolute_import
is the default on Python 3. Therefore from calendar import isleap
statement imports the top-level module calendar
.
If you see other results; it means either you are not using Python 3 or you are trying to run a python module from inside a package as a script (myproject
directory itself is in sys.path
). If the latter then your calendar.py
becomes the top-level module and (due to the current directory comes before stdlib directories in sys.path
) from calendar import isleap
imports calendar.py
from the current directory. "Never add a package directory, or any directory inside a package, directly to the Python path"
To avoid it, do not run modules from within python packages directly e.g., do not do this: cd myproject; python foo.py
. Do this instead: python -mmyproject.foo
(or you could define what scripts should be run in setup.py
or create a similar script manually: from myproject import foo; foo.main()
).
If you want to run a Python package as a script then create myproject/__main__.py
then run python -mmyproject
.
If you want to do a relative import in Python 3; do it explicitly e.g., in myproject/foo.py
:
from .calendar import something
Or do an absolute import:
from myproject.calendar import something
It looks like your path or directory structure is set up wrong.
Given the following structure the full name of your calendar module should be myproject.calendar
. You can check this by printing out the __name__
attribute of your module. For this to be the case, the path that your program uses to import local modules must be the folder containing myproject
.
myproject
├── calendar.py
├── foo.py
└── __init__.py
It seems like the path you are using is actually myproject
. Meaning calendar.py
is turned into the root level module calendar
, rather than myproject.calendar
. Python prefers local modules to builtin ones, and so imports your calendar
module.
More typically you might do something like this.
MyProjectFolder
├── main.py
└── myproject
├── calendar.py
├── foo.py
└── __init__.py
And then run your program like this:
#! /bin/bash
cd /path/to/MyProjectFolder
python main.py
Python will check your local modules and load them firstly by import
.
from calendar import isleap
will search the module calendar
in your locale package firstly. If not found, it will import from the builtin library calendar
.
from .calendar import isleap
will only import from your locale module calendar
. If not found, raises a exception ImportError
.
That is why you should use relative import in a package.
You can do a trick like that to import the builtin library without checking of the local modules. But it's only a trick. I will never use it in production. You should better rename your module calendar
.
import imp, sys
f, pathname, desc = imp.find_module("calendar", sys.path[1:])
calendar = imp.load_module("calendar", f, pathname, desc)
f.close()
from calendar import isleap