从字符串动态导入文件中的方法

我有一个字符串,比如: abc.def.ghi.jkl.myfile.mymethod。如何动态导入 mymethod

我是这么做的:

def get_method_from_file(full_path):
if len(full_path) == 1:
return map(__import__,[full_path[0]])[0]
return getattr(get_method_from_file(full_path[:-1]),full_path[-1])




if __name__=='__main__':
print get_method_from_file('abc.def.ghi.jkl.myfile.mymethod'.split('.'))

我想知道是否需要导入单独的模块。

编辑: 我使用的是 Python 2.6.5版。

126603 次浏览

使用 importlib(只适用于2.7 +)。

对于 Python < 2.7,可以使用内建方法 进口:

__import__('abc.def.ghi.jkl.myfile.mymethod', fromlist=[''])

对于 Python > = 2.7或3.1,已经添加了方便的方法 Import _ module:

importlib.import_module('abc.def.ghi.jkl.myfile.mymethod')

更新 : 根据评论更新版本(我必须承认,直到最后我才读取要导入的字符串,而且我忽略了一个事实,即应该导入模块的一个方法,而不是模块本身):

Python < 2.7:

mymethod = getattr(__import__("abc.def.ghi.jkl.myfile", fromlist=["mymethod"]))

Python > = 2.7:

mymethod = getattr(importlib.import_module("abc.def.ghi.jkl.myfile"), "mymethod")

您不需要导入单个模块。只需要导入要从中导入名称的模块并提供 fromlist参数即可:

def import_from(module, name):
module = __import__(module, fromlist=[name])
return getattr(module, name)

对于示例 abc.def.ghi.jkl.myfile.mymethod,将此函数调用为

import_from("abc.def.ghi.jkl.myfile", "mymethod")

(请注意,模块级函数在 Python 中称为函数,而不是方法。)

对于这样一个简单的任务,使用 importlib模块没有任何好处。

From Python 2.7 you can use the importlib.import_module() function. You can import a module and access an object defined within it with the following code:

from importlib import import_module


p, m = name.rsplit('.', 1)


mod = import_module(p)
met = getattr(mod, m)


met()

我倾向于这样做的方式(以及其他一些库,如高架和粘贴,如果我的记忆正确的话)是使用’:’在它们之间分离模块名称和函数/属性名称。请看下面的例子:

'abc.def.ghi.jkl.myfile:mymethod'

这使得下面的 import_from(path)函数更容易使用。

def import_from(path):
"""
Import an attribute, function or class from a module.
:attr path: A path descriptor in the form of 'pkg.module.submodule:attribute'
:type path: str
"""
path_parts = path.split(':')
if len(path_parts) < 2:
raise ImportError("path must be in the form of pkg.module.submodule:attribute")
module = __import__(path_parts[0], fromlist=path_parts[1])
return getattr(module, path_parts[1])




if __name__=='__main__':
func = import_from('a.b.c.d.myfile:mymethod')
func()

不清楚您要对本地名称空间做什么。我假设你想只是 my_method作为一个本地,键入 output = my_method()

# This is equivalent to "from a.b.myfile import my_method"
the_module = importlib.import_module("a.b.myfile")
same_module = __import__("a.b.myfile")
# import_module() and __input__() only return modules
my_method = getattr(the_module, "my_method")


# or, more concisely,
my_method = getattr(__import__("a.b.myfile"), "my_method")
output = my_method()

虽然您只将 my_method添加到本地命名空间,但您确实加载了模块链。您可以通过观察导入之前和之后的 sys.modules键来查看更改。我希望这比你其他的答案更清楚,更准确。

为了完整起见,这就是添加整个链的方法。

# This is equivalent to "import a.b.myfile"
a = __import__("a.b.myfile")
also_a = importlib.import_module("a.b.myfile")
output = a.b.myfile.my_method()


# This is equivalent to "from a.b import myfile"
myfile = __import__("a.b.myfile", fromlist="a.b")
also_myfile = importlib.import_module("a.b.myfile", "a.b")
output = myfile.my_method()

最后,如果您正在使用 __import__()并且在程序启动后修改了您的搜索路径,那么您可能需要使用 __import__(normal args, globals=globals(), locals=locals())。原因是一个复杂的讨论。

这个网站有一个很好的解决方案: Load _ class。我是这样使用它的:

foo = load_class(package.subpackage.FooClass)()
type(foo) # returns FooClass

根据要求,以下是网站链接的代码:

import importlib


def load_class(full_class_string):
"""
dynamically load a class from a string
"""


class_data = full_class_string.split(".")
module_path = ".".join(class_data[:-1])
class_str = class_data[-1]


module = importlib.import_module(module_path)
# Finally, we retrieve the Class
return getattr(module, class_str)
from importlib import import_module


name = "file.py".strip('.py')
# if Path like : "path/python/file.py"
# use name.replaces("/",".")


imp = import_module(name)


# get Class From File.py
model = getattr(imp, "classNameImportFromFile")


NClass = model() # Class From file

这样吧:

def import_module(name):


mod = __import__(name)
for s in name.split('.')[1:]:
mod = getattr(mod, s)
return mod