首页 文章

给定完整路径如何导入模块?

提问于
浏览
837

如何在完整路径下加载Python模块?请注意,该文件可以位于文件系统中的任何位置,因为它是一个配置选项 .

26 回答

  • 9

    听起来你不想专门导入配置文件(它有很多副作用和涉及的额外复杂性),你只想运行它,并能够访问生成的命名空间 . 标准库以runpy.run_path的形式专门为其提供API:

    from runpy import run_path
    settings = run_path("/path/to/file.py")
    

    该接口在Python 2.7和Python 3.2中可用

  • 0

    我为你做了一个使用 imp 的包 . 我称之为 import_file ,这就是它的用法:

    >>>from import_file import import_file
    >>>mylib = import_file('c:\\mylib.py')
    >>>another = import_file('relative_subdir/another.py')
    

    你可以在:

    http://pypi.python.org/pypi/import_file

    http://code.google.com/p/import-file/

  • 2

    要导入模块,您需要临时或永久地将其目录添加到环境变量中 .

    暂时

    import sys
    sys.path.append("/path/to/my/modules/")
    import my_module
    

    永久

    将以下行添加到 .bashrc 文件(在linux中)并在终端中执行 source ~/.bashrc

    export PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"
    

    信用/来源:saarrrranother stackexchange question

  • 16

    这应该工作

    path = os.path.join('./path/to/folder/with/py/files', '*.py')
    for infile in glob.glob(path):
        basename = os.path.basename(infile)
        basename_without_extension = basename[:-3]
    
        # http://docs.python.org/library/imp.html?highlight=imp#module-imp
        imp.load_source(basename_without_extension, infile)
    
  • 2

    我相信你可以使用imp.find_module()imp.load_module()来加载指定的模块 . 您需要将模块名称拆分为路径,即如果要加载 /home/mypath/mymodule.py ,则需要执行以下操作:

    imp.find_module('mymodule', '/home/mypath/')
    

    ......但那应该完成工作 .

  • -1

    创建python模块test.py

    import sys
    sys.path.append("<project-path>/lib/")
    from tes1 import Client1
    from tes2 import Client2
    import tes3
    

    创建python模块test_check.py

    from test import Client1
    from test import Client2
    from test import test3
    

    我们可以从模块导入导入的模块 .

  • 8

    这个答案是对Sebastian Rittau回答评论的答案的补充:"but what if you don't have the module name?"这是一种快速而又脏的方法,可以获得给定文件名的可能的python模块名称 - 它只是在树上,直到找到没有 __init__.py 文件的目录,然后把它变回文件名 . 对于Python 3.4(使用pathlib),这是有道理的,因为Py2人可以使用"imp"或其他方式进行相对导入:

    import pathlib
    
    def likely_python_module(filename):
        '''
        Given a filename or Path, return the "likely" python module name.  That is, iterate
        the parent directories until it doesn't contain an __init__.py file.
    
        :rtype: str
        '''
        p = pathlib.Path(filename).resolve()
        paths = []
        if p.name != '__init__.py':
            paths.append(p.stem)
        while True:
            p = p.parent
            if not p:
                break
            if not p.is_dir():
                break
    
            inits = [f for f in p.iterdir() if f.name == '__init__.py']
            if not inits:
                break
    
            paths.append(p.stem)
    
        return '.'.join(reversed(paths))
    

    肯定有改进的可能性,可选的 __init__.py 文件可能需要进行其他更改,但如果你有 __init__.py 一般,这就可以了 .

  • 3
    def import_file(full_path_to_module):
        try:
            import os
            module_dir, module_file = os.path.split(full_path_to_module)
            module_name, module_ext = os.path.splitext(module_file)
            save_cwd = os.getcwd()
            os.chdir(module_dir)
            module_obj = __import__(module_name)
            module_obj.__file__ = full_path_to_module
            globals()[module_name] = module_obj
            os.chdir(save_cwd)
        except:
            raise ImportError
    
    import_file('/home/somebody/somemodule.py')
    
  • 1

    你的意思是加载还是导入?

    您可以操作sys.path列表指定模块的路径,然后导入模块 . 例如,给出一个模块:

    /foo/bar.py
    

    你可以这样做:

    import sys
    sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path
    import bar
    
  • 1

    你可以使用

    load_source(module_name, path_to_file)
    

    方法来自imp module .

  • 3

    我想出了一个稍微修改过的@SebastianRittau's wonderful answer版本(我认为Python> 3.4),它允许你使用spec_from_loader而不是spec_from_file_location加载任何扩展名的文件作为模块:

    from importlib.util import spec_from_loader, module_from_spec
    from importlib.machinery import SourceFileLoader 
    
    spec = spec_from_loader("module.name", SourceFileLoader("module.name", "/path/to/file.py"))
    mod = module_from_spec(spec)
    spec.loader.exec_module(mod)
    

    在显式SourceFileLoader中编码路径的优点是machinery不会尝试从扩展中找出文件的类型 . 这意味着您可以使用此方法加载类似 .txt 文件的内容,但是如果没有指定加载器则无法使用 spec_from_file_location ,因为 .txt 不在importlib.machinery.SOURCE_SUFFIXES中 .

  • 2

    使用 importlib 而不是 imp 包的简单解决方案(针对Python 2.7进行了测试,尽管它也适用于Python 3):

    import importlib
    
    dirname, basename = os.path.split(pyfilepath) # pyfilepath: '/my/path/mymodule.py'
    sys.path.append(dirname) # only directories should be added to PYTHONPATH
    module_name = os.path.splitext(basename)[0] # '/my/path/mymodule.py' --> 'mymodule'
    module = importlib.import_module(module_name) # name space of defined module (otherwise we would literally look for "module_name")
    

    现在您可以直接使用导入模块的命名空间,如下所示:

    a = module.myvar
    b = module.myfunc(a)
    

    此解决方案的优点是 we don't even need to know the actual name of the module we would like to import ,以便在我们的代码中使用它 . 这很有用,例如如果模块的路径是可配置的参数 .

  • 335

    对于Python 3.5使用:

    import importlib.util
    spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py")
    foo = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(foo)
    foo.MyClass()
    

    对于Python 3.3和3.4使用:

    from importlib.machinery import SourceFileLoader
    
    foo = SourceFileLoader("module.name", "/path/to/file.py").load_module()
    foo.MyClass()
    

    (虽然这在Python 3.4中已被弃用 . )

    Python 2使用:

    import imp
    
    foo = imp.load_source('module.name', '/path/to/file.py')
    foo.MyClass()
    

    编译的Python文件和DLL有相同的便利功能 .

    也可以看看 . http://bugs.python.org/issue21436 .

  • 3

    我认为最好的方法来自官方文档(29.1. imp — Access the import internals):

    import imp
    import sys
    
    def __import__(name, globals=None, locals=None, fromlist=None):
        # Fast path: see if the module has already been imported.
        try:
            return sys.modules[name]
        except KeyError:
            pass
    
        # If any of the following calls raises an exception,
        # there's a problem we can't handle -- let the caller handle it.
    
        fp, pathname, description = imp.find_module(name)
    
        try:
            return imp.load_module(name, fp, pathname, description)
        finally:
            # Since we may exit via an exception, close fp explicitly.
            if fp:
                fp.close()
    
  • 6

    下面是一些适用于所有Python版本的代码,从2.7-3.5甚至其他版本 .

    config_file = "/tmp/config.py"
    with open(config_file) as f:
        code = compile(f.read(), config_file, 'exec')
        exec(code, globals(), locals())
    

    我测试了它 . 它可能很丑,但到目前为止是唯一一个适用于所有版本的产品 .

  • 3

    Python 3.4的这个区域似乎非常曲折,无法理解!然而,有一些黑客使用Chris Calloway的代码作为开始,我设法得到了一些工作 . 这是基本功能 .

    def import_module_from_file(full_path_to_module):
        """
        Import a module given the full path/filename of the .py file
    
        Python 3.4
    
        """
    
        module = None
    
        try:
    
            # Get module name and path from full path
            module_dir, module_file = os.path.split(full_path_to_module)
            module_name, module_ext = os.path.splitext(module_file)
    
            # Get module "spec" from filename
            spec = importlib.util.spec_from_file_location(module_name,full_path_to_module)
    
            module = spec.loader.load_module()
    
        except Exception as ec:
            # Simple error printing
            # Insert "sophisticated" stuff here
            print(ec)
    
        finally:
            return module
    

    这似乎使用了Python 3.4中不推荐使用的模块 . 我不假装理解为什么,但似乎在程序中起作用 . 我发现Chris的解决方案在命令行上运行,但不是在程序内部 .

  • 18

    如果您的顶级模块不是文件但是打包为__init__.py的目录,那么接受的解决方案几乎可以正常工作,但并不完全 . 在Python 3.5中,需要以下代码(请注意以'sys.modules'开头的添加行):

    MODULE_PATH = "/path/to/your/module/__init__.py"
    MODULE_NAME = "mymodule"
    spec = importlib.util.spec_from_file_location(MODULE_NAME, MODULE_PATH)
    module = importlib.util.module_from_spec(spec)
    sys.modules[spec.name] = module 
    spec.loader.exec_module(module)
    

    如果没有这一行,当执行exec_module时,它会尝试将顶级__init__.py中的相对导入绑定到顶级模块名称 - 在本例中为"mymodule" . 但"mymodule" isn 't loaded yet so you' ll得到错误"SystemError: Parent module 'mymodule' not loaded, cannot perform relative import" . 因此,您需要在加载名称之前绑定该名称 . 其原因是根本原因相对导入系统的不变量:"The invariant holding is that if you have sys.modules['spam'] and sys.modules['spam.foo'] (as you would after the above import), the latter must appear as the foo attribute of the former" as discussed here .

  • 19

    我并不是说它更好,但为了完整起见,我想建议exec函数,在python 2和3中都可用. exec 允许你在全局范围或内部执行任意代码范围,作为字典提供 .

    例如,如果您使用函数 foo() 存储了 "/path/to/module 中的模块,则可以通过执行以下操作来运行它:

    module = dict()
    with open("/path/to/module") as f:
        exec(f.read(), module)
    module['foo']()
    

    这使得您更加明确地表示您正在动态加载代码,并为您提供一些额外的功能,例如提供自定义内置功能的能力 .

    如果通过属性访问,而不是键对你很重要,你可以为全局变量设计一个自定义的dict类,它提供了这样的访问,例如:

    class MyModuleClass(dict):
        def __getattr__(self, name):
            return self.__getitem__(name)
    
  • 8

    向sys.path添加路径(使用imp)的优点是,当从单个包导入多个模块时,它简化了操作 . 例如:

    import sys
    # the mock-0.3.1 dir contains testcase.py, testutils.py & mock.py
    sys.path.append('/foo/bar/mock-0.3.1')
    
    from testcase import TestCase
    from testutils import RunTests
    from mock import Mock, sentinel, patch
    
  • 2

    您可以使用 pkgutil 模块(特别是walk_packages方法)获取当前目录中的包列表 . 从那里使用 importlib 机器导入所需的模块是微不足道的:

    import pkgutil
    import importlib
    
    packages = pkgutil.walk_packages(path='.')
    for importer, name, is_package in packages:
        mod = importlib.import_module(name)
        # do whatever you want with module now, it's been imported!
    
  • 5

    在Linux中,在python脚本所在的目录中添加符号链接 .

    即:

    ln -s /absolute/path/to/module/module.py /absolute/path/to/script/module.py
    

    python将创建 /absolute/path/to/script/module.pyc 并在更改 /absolute/path/to/module/module.py 的内容时更新它

    然后在mypythonscript.py中包含以下内容

    from module import *
    
  • 957

    将其添加到答案列表中,因为我找不到任何有用的东西 . 这将允许在3.4中导入已编译的(pyd)python模块:

    import sys
    import importlib.machinery
    
    def load_module(name, filename):
        # If the Loader finds the module name in this list it will use
        # module_name.__file__ instead so we need to delete it here
        if name in sys.modules:
            del sys.modules[name]
        loader = importlib.machinery.ExtensionFileLoader(name, filename)
        module = loader.load_module()
        locals()[name] = module
        globals()[name] = module
    
    load_module('something', r'C:\Path\To\something.pyd')
    something.do_something()
    
  • 0

    您也可以执行类似这样的操作,并将配置文件所在的目录添加到Python加载路径中,然后执行常规导入,假设您事先知道文件的名称,在本例中为“config” .

    凌乱,但它的确有效 .

    configfile = '~/config.py'
    
    import os
    import sys
    
    sys.path.append(os.path.dirname(os.path.expanduser(configfile)))
    
    import config
    
  • 0

    非常简单的方法:假设您想要具有相对路径的导入文件../../MyLibs/pyfunc.py

    libPath = '../../MyLibs'
    import sys
    if not libPath in sys.path: sys.path.append(libPath)
    import pyfunc as pf
    

    但是,如果你没有后卫,你终于可以走很长的路

  • 10

    要从给定文件名导入模块,您可以临时扩展路径,并在finally块reference:中恢复系统路径

    filename = "directory/module.py"
    
    directory, module_name = os.path.split(filename)
    module_name = os.path.splitext(module_name)[0]
    
    path = list(sys.path)
    sys.path.insert(0, directory)
    try:
        module = __import__(module_name)
    finally:
        sys.path[:] = path # restore
    
  • 8

    Import package modules at runtime (Python recipe)

    http://code.activestate.com/recipes/223972/

    ###################
    ##                #
    ## classloader.py #
    ##                #
    ###################
    
    import sys, types
    
    def _get_mod(modulePath):
        try:
            aMod = sys.modules[modulePath]
            if not isinstance(aMod, types.ModuleType):
                raise KeyError
        except KeyError:
            # The last [''] is very important!
            aMod = __import__(modulePath, globals(), locals(), [''])
            sys.modules[modulePath] = aMod
        return aMod
    
    def _get_func(fullFuncName):
        """Retrieve a function object from a full dotted-package name."""
    
        # Parse out the path, module, and function
        lastDot = fullFuncName.rfind(u".")
        funcName = fullFuncName[lastDot + 1:]
        modPath = fullFuncName[:lastDot]
    
        aMod = _get_mod(modPath)
        aFunc = getattr(aMod, funcName)
    
        # Assert that the function is a *callable* attribute.
        assert callable(aFunc), u"%s is not callable." % fullFuncName
    
        # Return a reference to the function itself,
        # not the results of the function.
        return aFunc
    
    def _get_class(fullClassName, parentClass=None):
        """Load a module and retrieve a class (NOT an instance).
    
        If the parentClass is supplied, className must be of parentClass
        or a subclass of parentClass (or None is returned).
        """
        aClass = _get_func(fullClassName)
    
        # Assert that the class is a subclass of parentClass.
        if parentClass is not None:
            if not issubclass(aClass, parentClass):
                raise TypeError(u"%s is not a subclass of %s" %
                                (fullClassName, parentClass))
    
        # Return a reference to the class itself, not an instantiated object.
        return aClass
    
    
    ######################
    ##       Usage      ##
    ######################
    
    class StorageManager: pass
    class StorageManagerMySQL(StorageManager): pass
    
    def storage_object(aFullClassName, allOptions={}):
        aStoreClass = _get_class(aFullClassName, StorageManager)
        return aStoreClass(allOptions)
    

相关问题