gpt4 book ai didi

python - 加载包但同名包已加载

转载 作者:行者123 更新时间:2023-12-01 08:55:08 25 4
gpt4 key购买 nike

我有同一个 Python 包的两个版本。我需要从当前版本的子包中的模块能够调用旧版本包中的函数(过去复制了自身)

我现在在哪里:

now/
package/
__init__.py
subpackage/
__init__.py
module.py -> "import package.subpackage.... <HERE>"
subpackage2/
...
...

旧版本:

past/
package/
__init__.py
subpackage/
__init__.py
module.py -> "import package.subpackage; from . import module2; .... def f(x) ..."
module2.py
subpackage2/
...
...

我需要导入<HERE> “旧”f并运行它。

理想情况

  • 函数f应该在旧包中生存,而不了解新版本包的任何信息
  • 新包中的模块应该调用它,让它继续存在,获取结果,然后完全忘记旧包的存在(因此在让 f 做她的事情后调用“import package.subpackage2”应该运行"new"版本)
  • 这样做应该不会太复杂

基本思想是通过保存我用于某些任务的代码以及输出数据,然后能够运行其中的一部分来提高可重复性。

遗憾的是,我知道这对于 Python 3 来说不是一个简单的任务,所以我准备接受某种妥协。我准备接受,例如运行旧的 f(x) 后名称package "new"代码中的内容将绑定(bind)到旧代码。

编辑

我使用importlib尝试了两种方式。这个想法是创建一个对象 mod然后做f = getattr(mod, "f") ,但是不起作用

  1. 改变sys.path['.../past/package/subpackage']然后调用importlib.import_module('package.subpackage.module') 。问题是,即使更改了sys.path,它也会加载“现在”中的那个。 ,可能是因为名字 package已经在 sys.modules
  2. spec = importlib.util.spec_from_file_location("module", "path..to..past..module.py"))
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    在这种情况下,相对导入 ( from . import module2.py ) 将不起作用,并给出错误“尝试在没有已知父包的情况下进行相对导入”

最佳答案

有一种方法可以非常简单地实现这一点,但您必须对旧包进行一些修改。

您只需在 now/package/old/__init__.py 中创建一个文件,其中包含:

__path__ = ['/absolute/path/to/old/package']

在新包中,您可以执行以下操作:

from package.old.package.subpackage.module import f as old_f

这里的问题是旧包尝试使用绝对导入来导入自己的包,它将从新包中加载内容。因此,旧包在从其自己的包导入内容时只能使用相对导入,否则您必须将 package.old 添加到旧包正在执行的所有绝对导入之前。

如果您愿意以这种方式修改旧包,那么应该没问题。如果该限制对您不起作用,请继续阅读。

如果您真的非常确定由于某些原因不想修改旧包。然后让我们做一些黑魔法,您需要将 builtins.__import__ 替换为您自己的版本,该版本根据谁进行导入而返回不同的模块。您可以通过检查调用堆栈来找出谁在进行导入。

例如,您可以这样做(在 Python 3.6 上测试):

import builtins
import inspect
import package.old

old_package_path = package.old.__path__[0]

OUR_PACKAGE_NAME = 'package'
OUR_PACKAGE_NAME_WITH_DOT = OUR_PACKAGE_NAME + '.'


def import_module(name, globs=None, locs=None, fromlist=(), level=0):
# only intercept imports for our own package from our old module
if not name.startswith(OUR_PACKAGE_NAME_WITH_DOT) or \
not inspect.stack()[1].filename.startswith(old_package_path):
return real_import(name, globs, locs, fromlist, level)

new_name = OUR_PACKAGE_NAME + '.old.' + name[len(OUR_PACKAGE_NAME_WITH_DOT):]
mod = real_import(new_name, globs, locs, fromlist, level)
return mod.old

# save the original __import__ since we'll need it to do the actual import
real_import = builtins.__import__
builtins.__import__ = import_module

builtins.__import__ 会在解释器遇到的任何导入语句上被调用,并且该调用不会被缓存,因此每次调用它时都可以返回不同的内容,即使它们使用相同的名称也是如此。

<小时/>

以下是我的旧答案,仅用于历史目的

我不太明白你想要做什么,但这很可能在Python 3中通过使用 importlib 来完成。 。

您只需创建一个模块加载器,从显式文件路径加载您的模块。

还有一个 invalidate_caches()reload() 函数,它们可能很有用,但您可能不需要它们。

关于python - 加载包但同名包已加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52822070/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com