我运行的是Python 2.5。

这是我的文件夹树:

ptdraft/
  nib.py
  simulations/
    life/
      life.py

(我在每个文件夹中都有__init__.py,为了可读性,这里省略了)

我如何从生命模块内导入nib模块?我希望不需要修改sys.path就可以做到。

注意:正在运行的主模块在ptdraft文件夹中。


当前回答

虽然这是违反所有规则的,但我还是想提一下这种可能性:

您可以先将文件从父目录复制到子目录。接下来导入它,然后删除复制的文件:

例如,在life.py中:

import os
import shutil

shutil.copy('../nib.py', '.')
import nib
os.remove('nib.py')

# now you can use it just fine:
nib.foo()

当然,当nibs尝试使用相对导入/路径导入/读取其他文件时,可能会出现一些问题。

其他回答

这里有一个简单的答案,你可以看到它是如何工作的,小而跨平台。 它只使用内置模块(os, sys和inspect),所以应该工作 因为Python就是为此而设计的。

更短的代码回答-更少的行和变量

from inspect import getsourcefile
import os.path as path, sys
current_dir = path.dirname(path.abspath(getsourcefile(lambda:0)))
sys.path.insert(0, current_dir[:current_dir.rfind(path.sep)])
import my_module  # Replace "my_module" here with the module name.
sys.path.pop(0)

如果行数少于这个数,请将第二行替换为import os。Path为Path, sys, inspect, 添加检查。在getsourcefile的开头(第3行)并删除第一行。 -然而,这会导入所有的模块,因此可能需要更多的时间,内存和资源。

我的答案代码(长版本)

from inspect import getsourcefile
import os.path
import sys

current_path = os.path.abspath(getsourcefile(lambda:0))
current_dir = os.path.dirname(current_path)
parent_dir = current_dir[:current_dir.rfind(os.path.sep)]

sys.path.insert(0, parent_dir)

import my_module  # Replace "my_module" here with the module name.

它使用了一个例子,从堆栈溢出回答如何获得当前的路径 在Python中执行文件?使用内置工具查找正在运行的代码的源(文件名)。

从inspect import getsourcefile 从操作系统。路径导入 接下来,无论你想从哪里找到源文件,你只需使用: abspath (getsourcefile(λ:0))

我的代码添加了一个文件路径到sys。Path, python路径列表 因为这允许Python从该文件夹导入模块。

在代码中导入模块后,在新行上运行sys.path.pop(0)是个好主意 当添加的文件夹具有与导入的另一个模块同名的模块时 稍后在节目中。您需要删除导入前添加的列表项,而不是其他路径。 如果您的程序没有导入其他模块,则不删除文件路径是安全的,因为 在程序结束后(或重新启动Python shell),对sys. exe所做的任何编辑。路径消失。

关于文件名变量的说明

我的回答没有使用__file__变量来获取运行的文件路径/文件名 代码,因为这里的用户经常描述它不可靠。你不应该用它 用于从其他人使用的程序的父文件夹中导入模块。

以下是一些行不通的例子(引用自这个Stack Overflow问题):

•它在某些平台上找不到•它有时不是完整的文件路径

Py2exe没有__file__属性,但有一个变通方法 当你使用execute()从IDLE运行时,没有__file__属性 OS X 10.6哪里我得到NameError:全局名称'__file__'没有定义

如果将模块文件夹添加到PYTHONPATH中失败,则可以修改sys. conf文件。Python解释器在你的程序中搜索要导入的模块的路径列表,Python文档说:

When a module named spam is imported, the interpreter first searches for a built-in module with that name. If not found, it then searches for a file named spam.py in a list of directories given by the variable sys.path. sys.path is initialized from these locations: the directory containing the input script (or the current directory). PYTHONPATH (a list of directory names, with the same syntax as the shell variable PATH). the installation-dependent default. After initialization, Python programs can modify sys.path. The directory containing the script being run is placed at the beginning of the search path, ahead of the standard library path. This means that scripts in that directory will be loaded instead of modules of the same name in the library directory. This is an error unless the replacement is intended.

知道了这一点,你可以在程序中执行以下操作:

import sys
# Add the ptdraft folder path to the sys.path list
sys.path.append('/path/to/ptdraft/')

# Now you can import your module
from ptdraft import nib
# Or just
import ptdraft

虽然原作者可能不再寻找解决方案,但为了完整,有一个简单的解决方案。它是像这样运行life.py模块:

cd ptdraft
python -m simulations.life.life

通过这种方式,您可以从nib.py导入任何东西,因为ptdraft目录在路径中。

与图书馆合作。 创建一个名为nib的库,使用setup.py安装它,让它驻留在站点包中,这样你的问题就解决了。 你不需要把你做的所有东西都装在一个包里。把它拆成碎片。

相对进口(如从..Import mymodule)只在包中工作。 导入当前模块父目录中的'mymodule':

import os
import sys
import inspect

currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir) 

import mymodule

编辑:__file__属性并不总是给定的。我现在建议使用inspect模块来检索当前文件的文件名(和路径),而不是使用os.path.abspath(__file__)