Python:如何导入包两次?

4

在同一个Python会话中,在不同的作用域下,以相同的名称两次导入包,在多线程环境下有方法吗?

我想导入包,然后覆盖其中一些函数,以便仅在特定类中使用时更改其行为。

例如,是否可能实现这样的功能?

import mod

class MyClass:

  mod = __import__('mod')

  def __init__():
     mod.function = new_function # override module function

  def method():
     mod.function() # call new_function

mod.function() # call original function

这可能听起来有些奇怪,但在这种情况下,使用改进的包的用户不需要更改他的代码。


关于这个问题,我想起了我的程序。它是这样的:import filename; print('import')。所以这个程序会导入/运行自己。我以为这会造成无限循环,但它只打印了两次“import”(所以它只导入了一次自己)。 - Remi Guan
为什么需要 mod = __import__('mod') 而不是简单的 mod = mod - Pynchia
2个回答

2

将模块导入为副本:

def freshimport(name):
    import sys, importlib
    if name in sys.modules:
        del sys.modules[name]
    mod = importlib.import_module(name)
    sys.modules[name] = mod
    return mod

测试:

import mymodule as m1
m2 = freshimport('mymodule')
assert m1.func is not m2.func

注意:

importlib.reload 不能完成此任务,因为它总是“考虑周到地”更新旧模块:

import importlib
import mymodule as m1
print(id(m1.func))
m2 = importlib.reload(m1)
print(id(m1.func))
print(id(m2.func))

示例输出:

139681606300944
139681606050680
139681606050680

谢谢你的回答。不幸的是,我认为这个解决方案不能让我在不同的作用域中加载具有相同名称的同一模块两次。 - Sisyphe
@Sisyphe 你可以将它简单地绑定到_相同的_ 本地 _名称_。 - Huazuo Gao

1
看起来需要上下文管理器来完成这个任务。
import modul

def newfunc():
    print('newfunc')

class MyClass:
    def __enter__(self):
        self._f = modul.func
        modul.func = newfunc
        return self

    def __exit__(self, type, value, tb):
        modul.func = self._f

    def method(self):
        modul.func()


modul.func()
with MyClass() as obj:
    obj.method()
    modul.func()
modul.func()

输出

func
newfunc
newfunc
func

其中 modul.py 包含以下内容

def func():
    print('func')

注意:此解决方案仅适用于单线程应用程序(在原帖中未指定)


感谢您的回答。这个解决方案在单线程环境下运行良好,但是在有两个线程运行各自的上下文管理器时,最后输入的对象将始终是设置全局函数的对象。如果我说错了,请纠正我。在这种情况下,覆盖超出了范围。 - Sisyphe
是的,这只是针对单线程应用程序的解决方案。我没有提到过它,因为您没有指定这样的限制。已编辑。 - Pynchia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接