我运行的是Python 2.5。
这是我的文件夹树:
ptdraft/
nib.py
simulations/
life/
life.py
(我在每个文件夹中都有__init__.py,为了可读性,这里省略了)
我如何从生命模块内导入nib模块?我希望不需要修改sys.path就可以做到。
注意:正在运行的主模块在ptdraft文件夹中。
我运行的是Python 2.5。
这是我的文件夹树:
ptdraft/
nib.py
simulations/
life/
life.py
(我在每个文件夹中都有__init__.py,为了可读性,这里省略了)
我如何从生命模块内导入nib模块?我希望不需要修改sys.path就可以做到。
注意:正在运行的主模块在ptdraft文件夹中。
当前回答
这里有一个简单的答案,你可以看到它是如何工作的,小而跨平台。 它只使用内置模块(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
我有一个问题,我必须导入一个Flask应用程序,它有一个导入,也需要在单独的文件夹中导入文件。这部分使用了Remi的答案,但假设我们有一个像这样的存储库:
.
└── service
└── misc
└── categories.csv
└── test
└── app_test.py
app.py
pipeline.py
然后,在从app.py文件导入app对象之前,我们将目录向上更改一层,因此当我们导入app(它导入了pipeline.py)时,我们也可以读入其他文件,如csv文件。
import os,sys,inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir)
os.chdir('../')
from app import app
在导入Flask应用程序之后,你可以使用os.chdir('./test'),这样你的工作目录就不会被改变。
我有一个专门针对git存储库的解决方案。
首先,我使用sys.path.append('..')和类似的解决方案。如果你导入的文件本身使用sys.path.append('..')导入文件,这会导致特别的问题。
然后我决定总是附加git存储库的根目录。在一行中是这样的:
sys.path.append(git.Repo('.', search_parent_directories=True).working_tree_dir)
或者更详细一点,像这样:
import os
import sys
import git
def get_main_git_root(path):
main_repo_root_dir = git.Repo(path, search_parent_directories=True).working_tree_dir
return main_repo_root_dir
main_repo_root_dir = get_main_git_root('.')
sys.path.append(main_repo_root_dir)
对于最初的问题:根据存储库的根目录,导入将是
import ptdraft.nib
or
import nib
虽然这是违反所有规则的,但我还是想提一下这种可能性:
您可以先将文件从父目录复制到子目录。接下来导入它,然后删除复制的文件:
例如,在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尝试使用相对导入/路径导入/读取其他文件时,可能会出现一些问题。
在Jupyter笔记本上(用Jupyter LAB或Jupyter Notebook打开)
只要你在木星笔记本上工作,这个简短的解决方案可能会有用:
%cd ..
import nib
即使没有__init__.py文件,它也能工作。
我在Linux和Windows 7上用Anaconda3测试了它。