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

问题描述 投票:924回答:26

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

python configuration python-import python-module
26个回答
1108
投票

对于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


12
投票

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

您可以操纵importlib.machinery.SOURCE_SUFFIXES列表指定模块的路径,然后导入模块。例如,给定一个模块:

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

你可以这样做:

sys.path

10
投票
/foo/bar.py

8
投票

我相信你可以使用import sys sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path import bar 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') 来加载指定的模块。您需要将模块名称拆分为路径,即如果要加载imp.find_module(),则需要执行以下操作:

imp.load_module()

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


4
投票

创建python模块test.py

/home/mypath/mymodule.py

创建python模块test_check.py

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

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


3
投票

这应该工作

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

3
投票

您可以使用from test import Client1 from test import Client2 from test import test3 模块(特别是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) 方法)来获取当前目录中的包列表。从那里使用pkgutil机器导入您想要的模块是微不足道的:

walk_packages

3
投票

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

importlib

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


3
投票

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

例如,如果你有一个模块存储在exec中“使用exec函数,你可以通过执行以下操作来运行它:

"/path/to/module

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

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

foo()

3
投票

要从给定文件名导入模块,您可以临时扩展路径,并在finally块中恢复系统路径module = dict() with open("/path/to/module") as f: exec(f.read(), module) module['foo']()

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

2
投票

我做了一个使用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 ,这就是它的用法:

imp

你可以在:

import_file

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


371
投票

向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
投票

2
投票

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

即:

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

python将创建################### ## # ## 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) 并将更新它,如果您更改ln -s /absolute/path/to/module/module.py /absolute/path/to/script/module.py 的内容

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

/absolute/path/to/script/module.pyc

1
投票

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

/absolute/path/to/module/module.py

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


1
投票

使用from module import * 而不是 libPath = '../../MyLibs' import sys if not libPath in sys.path: sys.path.append(libPath) import pyfunc as pf 包的简单解决方案(经过Python 2.7测试,虽然它也适用于Python 3):

importlib

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

imp

这个解决方案的优点是我们甚至不需要知道我们想要导入的模块的实际名称,以便在我们的代码中使用它。这很有用,例如如果模块的路径是可配置的参数。


0
投票

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

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")

0
投票

这个答案是对Sebastian Rittau回答评论的答案的补充:“但如果你没有模块名称怎么办?”这是一个快速而又脏的方法,可以获得给定文件名的可能的python模块名称 - 它只是在树上,直到找到没有a = module.myvar b = module.myfunc(a) 文件的目录,然后将其转回文件名。对于Python 3.4+(使用pathlib),这是有道理的,因为Py2人可以使用“imp”或其他方式进行相对导入:

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()

肯定有改进的可能性,可选的__init__.py文件可能需要进行其他更改,但如果你有一般的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)) ,这就行了。


-1
投票

我认为最好的方法来自官方文档(__init__.py):

__init__.py

20
投票

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

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

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


20
投票

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

MODULE_PATH = "/path/to/your/module/__init__.py"
MODULE_NAME = "mymodule"
import importlib
import sys
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”尚未加载,因此您将收到错误“SystemError:Parent module'mymodule'未加载,无法执行相对导入”。因此,您需要在加载名称之前绑定该名称。原因是相对导入系统的基本不变量:“不变量持有是如果你有sys.modules ['spam']和sys.modules ['spam.foo'](正如你在上面的导入之后那样) ),后者必须作为前者“as discussed here”的foo属性出现。


19
投票

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

凌乱,但它的确有效。

configfile = '~/config.py'

import os
import sys

sys.path.append(os.path.dirname(os.path.expanduser(configfile)))

import config

17
投票

你可以使用

load_source(module_name, path_to_file) 

来自imp module的方法。


17
投票

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

Temporarily

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

Permanently

将以下行添加到qazxsw poi文件(在linux中)并在终端中执行qazxsw poi:

.bashrc

信用/来源:source ~/.bashrcexport PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"


13
投票

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

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中。


12
投票

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

.txt

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

© www.soinside.com 2019 - 2024. All rights reserved.