在 Python 3 中动态导入模块的问题

2024-05-09

我遇到的情况是,在我的 Python 3 项目中,在运行时必须包含某些模块。我在用着importlib.import_module为了这。


第二次更新:我确实找到了一种方法来做一些接近我想要的事情。一些额外的代码可能会使我的一些链接稍微偏离一些。我将发布一个答案来展示我做了什么。



第一次更新:通过各种 Python 小组,我被告知这是不可能的。我在底部有一个更新部分。


设置

这个想法是,当用户运行我的脚本时,将搜索任何名为“agents_*.py”的文件(其中 * 被某个单词替换)以查找类并导入这些类。例如,一个名为agents_human.py将有一个名为HumanAgent。就是那个HumanAgent将被实例化的类,这就是为什么我需要导入模块(文件)以便发生这种情况。

基本问题

这个问题有两个方面:

  1. 我似乎无法让这个模块在多个目录中查找。
  2. 当我的程序安装时,导入模块根本不起作用。

问题背景

我有一个代码库显示了我正在尝试做的事情:https://github.com/jeffnyman/pacumen https://github.com/jeffnyman/pacumen

问题在于加载代理() https://github.com/jeffnyman/pacumen/blob/master/pacumen/__main__.py#L110方法;具体来说这个说法 https://github.com/jeffnyman/pacumen/blob/master/pacumen/__main__.py#L132.

为了说明这一点,如果您克隆该存储库,则可以从项目根目录运行以下命令:

python3 -m pacumen
  • That 将工作 if the agents_human.py文件位于项目的根目录中。
  • It will not工作,如果agents_human.py文件是一个agents项目内的目录。

在我的代码仓库中,agents_human.py文件位于agents目录,因此导入失败。但如果该文件被移动到根目录,您会看到导入有效。然而,正如在load_agent()函数中,我已将当前工作目录加上“agents”目录添加到路径中(第 119 - 121 行 https://github.com/jeffnyman/pacumen/blob/master/pacumen/__main__.py#L119)

当我说导入失败时,我的意思是:当调用导入逻辑时,the ImportError例外 https://github.com/jeffnyman/pacumen/blob/master/pacumen/__main__.py#L133被触发。再次强调,这仅当agents_human.py文件位于agents目录。

待解决的问题

理想情况下,我希望这适用于两种方法:当文件位于根目录中时以及当文件位于agents目录。

其他问题背景

我只是打算忍受必须将文件放在根目录中。但是,更糟糕的是,当安装程序(而不是从项目根目录运行)时,即使上面有效的部分也不再有效。

具体来说,从克隆项目的项目根目录中,我执行以下操作:

pip3 install .

然后我创建一些目录(比如说,test_pacumen)。在那里我放了一个agents_human.py文件的唯一内容是:

class HumanAgent:
  pass

(还需要的是layouts我的项目目录。)

然后我运行:

pacumen

在这种情况下,逻辑永远不会导入agents_human.py文件...即使它位于执行命令的根目录中。

我尝试过什么

通过查看各种示例,我的理解是我必须通过相对名称或提供显式锚点进行导入。但这似乎是通过提供在其中搜索模块的路径来实现的。我上面链接的代码似乎就是这样做的。

我得到了在路径上找到的模块名称(通过这条线 https://github.com/jeffnyman/pacumen/blob/master/pacumen/__main__.py#L128)并且在所有情况下,它都会找到我放置的相关文件。所以看起来路径正在工作;不是导入。这就是我找不到很多指导的地方。

我还尝试以这种方式获取每个文件路径的路径结尾部分:

module_end_dir = os.path.basename(os.path.normpath(module_dir))

然后,有了这个,我尝试了这个:

agent_module = importlib.import_module(f"{module_end_dir}.{module_name[:-3]}")

这在本地有效agents_human.py在里面agents目录,但如果agents_human.py是在根部。而且当程序安装后仍然根本不起作用。

问题总结

  1. 在第一个问题上下文(未安装的上下文)中,我不知道为什么agents_human.py模块无法导入agents但可以从根导入。

  2. 在第二个上下文(已安装)中,似乎agents_human.py即使模块位于根目录中,也无法导入。

我希望我在这里提供的内容不会太令人困惑。

UPDATE:

我得到了为我的孩子尝试这样的想法load_agent功能:

def load_agent(pacman, not_human):
  module = importlib.import_module("agents.agents_human")
  return getattr(module, pacman)

当程序通过其项目根运行时,这确实有效,但当项目通过 pip 安装时,这不起作用。显然,这与脚本的入口点以及 Python 如何无法将目录识别为该上下文中的模块有关。

提供了我想到的另一个例子:

def load_agent(pacman, not_human):
  import re
  pysearchre = re.compile('.py$', re.IGNORECASE)
  agent_files = filter(pysearchre.search, os.listdir(os.path.join(os.getcwd(), 'agents')))
  form_module = lambda fp: '.' + os.path.splitext(fp)[0]
  agents = map(form_module, agent_files)

  importlib.import_module('agents')

  for agent in agents:
      if not agent.startswith('__'):
          agent_module = importlib.import_module(agent, package="agents")

  if pacman in dir(agent_module):
      return getattr(agent_module, pacman)

  raise Exception("The agent " + pacman + " is not specified in any agents_*.py file.")

同样的情况。无需安装即可运行该程序;安装程序时不会。

这基本上是为了确认当通过 pip 安装 Python 程序时我想做的事情是不可能的。我不是entirely深信不疑,但我包含此更新以防其他人遇到此情况。


由于您的入口点,您正在做的事情将不起作用setup.py而且还因为 Python 没有你的概念agents安装程序时的目录。

您可以尝试将代理路径添加到 sys.path:

sys.path.insert(0, os.getcwd() + '/agents')

但我怀疑当有人安装你的程序时这是否有效。 (当您发现程序从项目运行时,您不需要这样做。)当您直接从项目本身运行它时,通过 pip 安装基本上将执行脚本与目录上下文分开。

您可以尝试的另一件事是通过文件位置导入。换句话说,不要对待你的agents目录(来自安装)作为实际模块。相反,只需将其视为其本来面目:目录位置。问题是,这是 Python 在版本之间搞砸事情的另一个领域。

如果您使用的是 3.5 及更高版本,您可以执行以下操作:

import importlib.util
spec = importlib.util.spec_from_file_location("agents.agent_human", "/agents/agents_human.py")
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)

如果您使用的是 Python 3.3 或 3.4,您可以执行以下操作:

from importlib.machinery import SourceFileLoader
foo = SourceFileLoader("agents.agent_human", "/agents/agents_human.py").load_module()

但请注意,即使在 Python 3.4 中,这也已被弃用。

您可能想尝试这些的一些变化。您可能需要添加一些逻辑来检查中的任何文件agents目录,假设您想尝试在该目录中的所有文件中查找该类。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Python 3 中动态导入模块的问题 的相关文章

  • 从 asyncio 子进程获取实时输出

    我正在尝试使用 Python asyncio 子进程来启动交互式 SSH 会话并自动输入密码 实际用例并不重要 但它有助于说明我的问题 这是我的代码 proc await asyncio create subprocess exec ssh
  • 使用 pyppeteer 与 asyncio 关联来抓取内容

    我用 python 结合编写了一个脚本pyppeteer随着asyncio从其登陆页面抓取不同帖子的链接 并最终通过跟踪通向其内页的 url 来获取每个帖子的标题 我这里解析的内容不是动态的 但是 我利用了pyppeteer and asy
  • 嵌套函数中的变量作用域

    有人可以解释为什么以下程序失败 def g f for in range 10 f def main x 10 def f print x x x 1 g f if name main main 带有消息 Traceback most re
  • 用于读取类似 CSV 行的 Python 正则表达式

    我想解析传入的类似 CSV 的数据行 值用逗号分隔 逗号周围可能有前导和尾随空格 并且可以用 或 引用 例如 这是有效的行 data1 data2 data3 data4 data5 但这是格式错误的 data1 data2 da ta3
  • 如何使用 Pycharm 运行 fast-api 服务器?

    我有一个简单的 API 函数 如下所示 from fastapi import FastAPI app FastAPI app get async def read root return Hello World 我正在使用启动服务器uvi
  • 如何进行重定向并保留查询字符串?

    我想进行重定向并保留查询字符串 就像是self redirect加上发送的查询参数 那可能吗 newurl my new route urllib urlencode self request params self redirect ne
  • FastAPI UploadFile 与 Flask 相比慢

    我创建了一个端点 如下所示 app post report upload def create upload files files UploadFile File try with open files filename wb as wf
  • python win32com.client 调整窗口大小

    我正在使用 Python 3 4 1 通过 win32com client 控制 Windows 应用程序 我可以激活它 我可以发送击键 点击等 现在我想知道是否有办法调整窗口大小并将其设置到特定位置 我找不到方法 这里有一些代码片段 所以
  • 如何使用 Python 在表单中选择选项?

    我想知道如何以格式如下的形式选择选项 td align left td
  • numpy 向量化而不是 for 循环

    我用 Python 写了一些代码 运行良好 但速度很慢 我认为是由于 for 循环 我希望可以使用 numpy 命令加速以下操作 让我定义目标 假设我有一个 2D numpy 数组all CMs尺寸row x col 例如考虑一个6x11数
  • 数据类和属性装饰器

    我一直在阅读 Python 3 7 的数据类 作为命名元组的替代品 我通常在必须将数据分组到结构中时使用它 我想知道数据类是否与属性装饰器兼容 以便为数据类的数据元素定义 getter 和 setter 函数 如果是这样 是否在某处进行了描
  • 我应该在哪里对对象和字段进行 django 验证?

    我正在创建一个 Django 应用程序 它使用 Django Rest Framework 和普通的 django views 作为用户的入口点 我想对模型的独立字段以及整个对象进行验证 例如 字段 根据正则表达式函数输入的车牌是否正确 与
  • 如何在 Jupyter Notebook 中选择 conda 环境

    我安装了 Anaconda 5 3 和 Python 3 7 根环境 之后我使用 Python 3 6 创建了一个新环境 py36 我激活了新环境activate py36 conda env list表明环境是活跃的 但是当我启动 Jup
  • python 中“重载”函数的最佳方法? [复制]

    这个问题在这里已经有答案了 我正在尝试在 python 中做这样的事情 def foo x y do something at position x y def foo pos foo pos x pos y 所以我想根据我提供的参数数量调
  • 如何通过 API Gateway 使用事件调用类型调用 Lambda 函数?

    文件说 默认情况下 Invoke API 采用 RequestResponse 调用类型 您可以选择通过将 Event 指定为 InitationType 来请求异步执行 因此 我可以发送到我的函数 python 的就是到处都是 Inspi
  • 如何在Python中不使用库函数将字符串转换为整数?

    我正在尝试转换 a 546 to a 546 不使用任何库函数 我能想到的 最纯粹 gt gt gt a 546 gt gt gt result 0 gt gt gt for digit in a result 10 for d in 01
  • 如何将另一整列作为参数传递给 pandas fillna()

    我想用另一列中的值填充一列中的缺失值 使用fillna方法 我读到循环遍历每一行将是非常糟糕的做法 最好一次完成所有事情 但我不知道如何使用fillna 之前的数据 Day Cat1 Cat2 1 cat mouse 2 dog eleph
  • 如何从 Anaconda 更新 Pandas 以及最后是否可以使用 eclipse

    我已经使用以下文档通过 Anaconda 安装了 Python http www kevinsheppard com images 0 09 Python introduction pdf http www kevinsheppard co
  • Python 中的可逆 STFT 和 ISTFT

    有没有通用的形式短时傅立叶变换 https en wikipedia org wiki Short time Fourier transform与内置于 SciPy 或 NumPy 或其他什么中的相应逆变换 这是pyplotspecgram
  • Python 子进程:无法转义引号

    我知道以前曾问过类似的问题 但它们似乎都是通过重新设计参数的传递方式 即使用列表等 来解决的 但是 我这里有一个问题 因为我没有这个选项 有一个特定的命令行程序 我使用的是 Bash shell 我必须向其传递带引号的字符串 它不能不被引用

随机推荐