这是导入驻留在任意文件夹中的python脚本的正确方法吗?

时间:2010-06-29 03:50:06

标签: python

这个片段来自SO的早期答案。它大约一岁(答案未被接受)。我是Python的新手,我发现系统路径真的很痛苦。我有一些用不同目录的脚本编写的函数,我希望能够将它们导入到新项目中,而不必跳过箍。

这是片段:

def import_path(fullpath):
""" Import a file with full path specification. Allows one to
    import from anywhere, something __import__ does not do. 
"""
path, filename = os.path.split(fullpath)
filename, ext = os.path.splitext(filename)
sys.path.append(path)
module = __import__(filename)
reload(module) # Might be out of date
del sys.path[-1]
return module

它来自这里: How to do relative imports in Python?

我想要一些关于我是否可以使用它的反馈 - 如果有任何不良副作用对新手来说可能不明显。

我打算用它这样的东西:

import_path(/home/pydev/path1/script1.py)

script1.func1()

以我想要的方式使用该功能是否“安全”?

4 个答案:

答案 0 :(得分:8)

“官方”和完全安全的方法是标准Python库的imp模块。

使用imp.find_module在精确指定的可接受目录列表中查找模块 - 它返回一个3元组(file, pathname, description) - 如果不成功,file实际上是{{1} (但它也可以提升None,因此您应该使用ImportError / try来检查except

如果搜索成功,请在第一个参数之后调用imp.load_module(在if file is None: / try中确保关闭文件!)传递给finally的{​​{1}} - 它返回模块对象(phew; - )。

答案 1 :(得分:1)

如上所述,如果合适,请考虑线程安全。我更喜欢更贴近类似帖子中发布的解决方案。主要区别如下:使用insert指定导入的优先级,使用try ... finally正确恢复sys.path,并设置全局命名空间。

# inspired by Alex Martelli's solution to
# http://stackoverflow.com/questions/1096216/override-namespace-in-python/1096247#1096247
def import_from_absolute_path(fullpath, global_name=None):
    """Dynamic script import using full path."""
    import os
    import sys

    script_dir, filename = os.path.split(fullpath)
    script, ext = os.path.splitext(filename)

    sys.path.insert(0, script_dir)
    try:
        module = __import__(script)
        if global_name is None:
            global_name = script
        globals()[global_name] = module
        sys.modules[global_name] = module
    finally:
        del sys.path[0]

答案 2 :(得分:0)

它确实感觉有点像黑客,但目前,我想不出任何可能发生的意外副作用,至少不会只是你只是将它用于你自己的脚本。基本上它的作用是暂时将指定文件的父目录(在您的示例中为/home/pydev/path1/)添加到Python在查找要导入的模块时检查的路径列表。

我现在能想到的唯一风险是在多线程环境中出现,其中两个或多个线程(或进程)同时运行此功能。如果线程A想要从路径dirA/A.py导入模块A,并且线程B想要从路径dirB/B.py导入模块B,那么你最终会同时使用dirAdirBsys.path短时间内。如果B.py中有一个名为dirA的文件,则线程B可能会找到(dirA/B.py)而不是它正在寻找的文件(dirB/B.py),因此导入错误的模块。出于这个原因,我不会在生产代码或您要分发给其他人的代码中使用它(至少在没有警告他们这个hack就在这里的情况下!)。在这种情况下,您可以编写一个更复杂的函数,允许您指定要导入的文件,而不会弄乱标准的路径集。 (这就是mod_python所做的事情)

答案 3 :(得分:0)

我担心您的脚本名称可能与路径中较早显示的模块相对应。为了消除这种担心,我会用一个只包含该模块的目录的新列表完全替换该路径,然后在导入完成后将其放回。另外,你应该将它包装在某种锁中,以便尝试做同样事情的多个线程不会相互干扰。