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..
-
What is your question?zondo– zondo2016年05月10日 12:55:45 +00:00Commented May 10, 2016 at 12:55
-
The question is..why is my local calendar module being loaded?Godsent– Godsent2016年05月10日 12:56:53 +00:00Commented May 10, 2016 at 12:56
-
Because that is the first location that a module is being searched in.DeepSpace– DeepSpace2016年05月10日 13:03:07 +00:00Commented May 10, 2016 at 13:03
-
1That's normal. Python load the local module first.qvpham– qvpham2016年05月10日 13:10:55 +00:00Commented May 10, 2016 at 13:10
-
1@julivico ah..thanks..I was under the impression that the explicit import requires to use .calendar for the local module and without it it goes the build-in.. just my own imagination I suppose! :) I'm guessing the sensible way to solve this is to rename my module then..Godsent– Godsent2016年05月10日 13:35:09 +00:00Commented May 10, 2016 at 13:35
3 Answers 3
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
Comments
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
Comments
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