如何在运行时制作python模块的副本? [英] How to make a copy of a python module at runtime?

查看:109
本文介绍了如何在运行时制作python模块的副本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要复制一个套接字模块才能使用它,并需要对另一个套接字模块进行猴子修补并以不同的方式使用它.

I need to make a copy of a socket module to be able to use it and to have one more socket module monkey-patched and use it differently.

这可能吗?

我的意思是真正复制一个模块,即在运行时上获得相同的结果,就像我复制了socketmodule.c一样,将initsocket()函数更改为initmy_socket()并安装了它作为my_socket扩展名.

I mean to really copy a module, namely to get the same result at runtime as if I've copied socketmodule.c, changed the initsocket() function to initmy_socket(), and installed it as my_socket extension.

推荐答案

您始终可以执行一些技巧,例如导入模块,然后将其从sys.modules中删除或尝试复制模块.但是,Python已经在其标准库中提供了所需的内容.

You can always do tricks like importing a module then deleting it from sys.modules or trying to copy a module. However, Python already provides what you want in its Standard Library.

import imp # Standard module to do such things you want to.

# We can import any module including standard ones:
os1=imp.load_module('os1', *imp.find_module('os'))

# Here is another one:
os2=imp.load_module('os2', *imp.find_module('os'))

# This returns True:
id(os1)!=id(os2)

Python3.3 +

imp.load_module在python3.3 +中弃用的 ,并建议使用importlib

Python3.3+

imp.load_module is deprecated in python3.3+, and recommends the use of importlib

#!/usr/bin/env python3

import sys
import importlib.util

SPEC_OS = importlib.util.find_spec('os')
os1 = importlib.util.module_from_spec(SPEC_OS)
SPEC_OS.loader.exec_module(os1)
sys.modules['os1'] = os1

os2 = importlib.util.module_from_spec(SPEC_OS)
SPEC_OS.loader.exec_module(os2)
sys.modules['os2'] = os2
del SPEC_OS

assert os1 is not os2, \
    "Module `os` instancing failed"

在这里,我们两次导入相同的模块,但作为完全不同的模块对象.如果检查sys.modules,则可以看到您输入的两个名称作为load_module调用的第一个参数.查看文档以了解详细信息.

Here, we import the same module twice but as completely different module objects. If you check sys.modules, you can see two names you entered as first parameters to load_module calls. Take a look at the documentation for details.

更新:

为使这种方法的主要区别显而易见,我想更清楚一点:以这种方式导入同一模块时,对于在运行时导入的所有其他模块,都可以全局访问这两个版本.据我了解,提问者的需求.

To make the main difference of this approach obvious, I want to make this clearer: When you import the same module this way, you will have both versions globally accessible for every other module you import in runtime, which is exactly what the questioner needs as I understood.

下面是另一个强调这一点的例子.

Below is another example to emphasize this point.

这两个语句做的完全相同:

These two statements do exactly the same thing:

import my_socket_module as socket_imported

socket_imported = imp.load_module('my_socket_module',
    *imp.find_module('my_socket_module')
)

在第二行,我们重复两次'my_socket_module'字符串,这就是import语句的工作方式;但是实际上使用这两个字符串有两个不同的原因.

On second line, we repeat 'my_socket_module' string twice and that is how import statement works; but these two strings are, in fact, used for two different reasons.

第二次出现在我们将其传递给find_module时,将用作在系统上找到的文件名.当我们将字符串传递给load_module方法时,该字符串的首次出现用作已加载模块的系统范围标识符.

Second occurrence as we passed it to find_module is used as the file name that will be found on the system. The first occurrence of the string as we passed it to load_module method is used as system-wide identifier of the loaded module.

因此,我们可以为它们使用不同的名称,这意味着我们可以使其完全像复制模块的python源文件并加载它一样工作.

So, we can use different names for these which means we can make it work exactly like we copied the python source file for the module and loaded it.

socket = imp.load_module('socket_original', *imp.find_module('my_socket_module'))
socket_monkey = imp.load_module('socket_patched',*imp.find_module('my_socket_module'))

def alternative_implementation(blah, blah):
    return 'Happiness'

socket_monkey.original_function = alternative_implementation

import my_sub_module

然后在my_sub_module中,我可以导入系统上不存在的'socket_patched'!在这里,我们在my_sub_module.py中.

Then in my_sub_module, I can import 'socket_patched' which does not exist on system! Here we are in my_sub_module.py.

import socket_patched
socket_patched.original_function('foo', 'bar')
# This call brings us 'Happiness'

这篇关于如何在运行时制作python模块的副本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆