关于python:如何导入标准库模块而不是本地目录?

How to import standard library module instead of local directory?

我有一个名为"calendar"的本地目录,其中包含"__init__.py"文件。

我希望"导入日历"导入标准库模块日历,而不是我本地目录定义的模块。

我已经尝试过"从__future__ import absolute_import"并改变PYTHONPATH。

有很好的理由我不能只重命名目录。 真。


问题是,启动Python时,当前工作目录(作为'''.',取决于版本/平台)始终位于sys.path的顶部。

使用绝对导入没有区别 - 这只是首先查看sys.path,而不是在回退到sys.path之前查找相对导入。

正确的解决方案显然是(a)重命名calendar,或(b)将其移动到其他包的子包中,而不是将其放在顶层。无论你的好理由是什么,做正确的事情的好理由可能更好。

但如果你必须解决这个问题,你可以做一些事情。最简单的是暂时munge sys.path

1
2
3
4
syspath = sys.path
sys.path = [path for path in sys.path if path.strip('.')]
import calendar
sys.path = syspath

但是,无论你做什么,这都会造成巨大的问题。当你以后尝试导入本地包calendar时 - 如果你是从一个完全不同的源文件中这样做的话 - 什么都不会发生,因为sys.modules中已经有一些名为calendar的东西,所以其他的源文件将会只需获取stdlib calendar模块而不是您的包。

因此,您还需要动态重命名其中一个,并将其从sys.modules中删除。也许这个:

1
2
3
4
5
6
7
syspath = sys.path
sys.path = [path for path in sys.path if path.strip('.')]
calmod = sys.modules.get('calendar')
del sys.modules['calendar']
calendar = __import__('calendar')
sys.modules['calendar'] = calmod
sys.path = syspath

而且,根据模块运行的顺序(可能不容易预测,甚至是确定性的),您很可能在其他位置需要类似的hackery。

(如果你真的不需要导入你的本地包calendar怎么办呢?那么,在这种情况下你没有这个问题......但是我无法想象你的好理由可能是什么......)


您可以修改sys.path,导入包,然后将sys.path恢复为其原始值。

1
2
3
4
5
import sys
original_path = sys.path
sys.path = original_path[1:]
import calendar
sys.path = original_path


正如其他人所说,最好的选择是将日历模块重命名为标准库未使用的新模块。

但是作为一种解决方法,如果不可能,您可以在放置本地calendar.py文件的目录之外创建另一个模块(在syspath中可见)。

所以如果你有这样的层次结构:

1
2
3
4
5
6
project/
   __init__.py
   app1/
      __init__.py
      calendar.py
      module_in_which_i_want_to_use_python_std_calendar.py

您可以在应用程序外部创建名为std_calendar.py的新模块(在calendar.py之外放置)。在此文件中,您可以导入日历(这将是标准日历模块)

1
from calendar import *

层次结构将是:

1
2
3
4
5
6
7
project/
   __init__.py
   std_calendar.py
   app1/
      __init__.py
      calendar.py
      module_in_which_i_want_to_use_python_std_calendar.py

module_in_which_i_want_to_use_python_std_calendar.py中,您可以使用标准日历:

1
from project import std_calendar as calendar