Django 绝对导入

2 投票
2 回答
2831 浏览
提问于 2025-04-18 07:11

假设有一个系统级的模块叫做 foobar,还有一个名为 foobar 的 Django 应用程序,而我不能修改这两个项目,因为它们都是外部的。

现在,我想使用系统的 foobar 模块,而不是这个应用程序,但它不工作:

$ python --version
Python 2.7.3

$ ./manage.py --version
1.3.1

$ ./manage.py shell
>>> import foobar
>>> print (foobar)
<module 'foobar' from '/path/to/myproject/foobar/__init__.pyc'>

我该怎么做呢?我想我应该能得到 <module 'foobar' from '/usr/lib/python2.7/dist-packages/foobar/__init__.pyc'> 这样的结果。

2 个回答

1

试试这个,不要写死路径

import os
import sys
PROJECT_DIR = os.path.dirname(__file__) 
# make sure the path is right, it depends on where you put the file is

# If PROJECT_DIR in sys.path, remove it and append to the end.
syspath = sys.path
syspath_set = set(syspath)
syspath_set.discard(PROJECT_DIR)
sys.path = list(syspath_set)

sys.path.append(PROJECT_DIR)

# Then try
import foobar

# At last, change it back, prevent other import mistakes
sys.path = syspath
2

Python会在环境变量PYTHONPATH定义的位置寻找包。你可以很简单地在Python内部修改这个路径:

https://docs.python.org/2/install/index.html#modifying-python-s-search-path

你需要修改sys.path,让包含系统的foobar模块的目录在应用程序目录之前。

假设你的sys.path看起来像这样:

>>> import sys
>>> sys.path
['', '/usr/local/lib/python2.7/site-packages']

如果foobar同时在当前工作目录(用''表示)和系统的site-packages目录中,你需要把系统的foobar放到列表的前面:

>>> sys.path.insert(0, '/usr/local/lib/python2.7/site-packages/foobar')
>>> sys.path
['/usr/local/lib/python2.7/site-packages/foobar', 
 '', '/usr/local/lib/python2.7/site-packages']

请注意,这个路径的修改只会对当前运行的Python进程(在这个例子中是交互式会话)有效,之后的进程会使用原来的路径。

不修改路径的解决方案

如果你不能或者不想修改sys.path,可以使用imp模块手动导入一个模块:

import imp

name = 'foobar'
path = '/usr/local/lib/python2.7/site-packages/foobar'

fp, pathname, description = imp.find_module(name, path)
try:
    imp.load_module(name, fp, pathname, description)
finally:
    # Make sure the file pointer was closed:
    if fp:
        fp.close()

临时修改路径的解决方案

这个解决方案不需要提前知道系统foobar包的位置,只需要知道你想要的那个不是在当前目录中的:

import imp
import sys

# Temporarily remove the current working directory from the path:
cwd = sys.path.pop(0)

# Now we can import the system `foobar`:
import foobar

# Put the current working directory back where it belongs:
sys.path.insert(0, cwd)

撰写回答