在Python中通过变量动态导入相对脚本

1 投票
3 回答
954 浏览
提问于 2025-04-18 04:56

在我的主要Python脚本中,我会调用一个网络API。这个调用的结果决定了需要运行哪个“协议”。这些协议是放在一个叫做protocols/的子文件夹里的独立Python脚本。

那么,从我的主脚本中,我该如何动态地调用其中一个脚本呢?脚本的名字是从API得到的一个变量,而且它是在主脚本的子文件夹里,而不是在标准库的位置。

我可以使用subprocess.popen或者os.system来实现,但我希望尽量保持所有内容都在内部处理。

总得有办法在一个Python实例中完成这个吧,对吧?

3 个回答

0

是的,可以在一个Python实例中实现这个功能。你可以动态加载单独的Python脚本,方法如下:

  1. 使用 importlib.import_module() 动态加载模块。
  2. 使用 getattr() 动态加载模块和类。

方法一

如果你只想动态加载模块,可以使用 importlib.import_module()。假设你在一个名为 protocols 的子文件夹中有以下协议:

protocols/protocol_1.py 里面有以下类:

class Protocol():
    # some protocol specific code

protocols/protocol_2.py 里面有以下类:

class Protocol():
    # some protocol specific code

首先,我们定义动态变量,变量名是从Web API返回的协议名称:

module = 'protocols.protocol_1' 

然后我们导入importlib并动态加载模块。两个文件中的Protocol类名字相同,但里面的代码是针对不同协议的。接着,我们用动态加载的Protocol实例化api_protocol:

import importlib

Protocol = importlib.import_module(module).Protocol

api_protocol = Protocol()

方法二

如果你还想动态加载类,可以使用getattr。假设你在 protocols 子文件夹中有以下协议:

protocols/protocol_1.py 里面有以下类:

class Protocol_1():
    # some protocol specific code

protocols/protocol_2.py 里面有以下类:

class Protocol_2():
    # some protocol specific code

首先,我们定义动态变量,变量名是从Web API返回的协议名称:

module = 'protocols.protocol_1' 
class_name = 'Protocol_1'

然后我们调用 __import__ 函数来动态加载一个动态 模块。之后,我们可以使用 getattr 创建新的类,并用动态加载的Protocol实例化api_protocol:

mod = __import__(module, fromlist=[class_name])
Protocol = getattr(mod, class_name)
api_protocol = Protocol()
0

Python有一个内置的函数,可以用来调用脚本。

这个函数叫做 execfile,你可以在这里了解更多信息:

https://docs.python.org/2/library/functions.html#execfile

假设我有一个文件叫 testmeagain.py,里面的内容是:

print "test print"

你可以在不导入额外库的情况下做到这一点:

In [1]: execfile("testmeagain.py")
test print
0

假设你从一个文件夹里运行你的主Python程序,这个文件夹里有一个叫做protocols的子文件夹。你需要在protocols文件夹里添加一个空的__init__.py文件,这样它就变成了一个包。

之后,你就可以从这个包里导入特定的模块,比如:

from protocols.http import process_it

在这里,我假设你会在里面有一个叫process_it的函数。

还有其他方法可以导入包,方法名是通过变量定义的,具体可以参考这个SO的回答 点击这里查看链接

在你的情况下,代码可能看起来像这样:

def process_it(protocol="http"):
    mod = __import__("protocols." + protocol)
    mod.process_it()

撰写回答