如何在python中重载内置模块



我正在尝试将主机绑定到我的python程序中的指定ip。只要让它在python程序中生效,所以我不会修改/etc/hosts文件。

我尝试在socket.py中的create_connection函数中添加一个位代码,用于主机ip翻译,如下所示:

host, port = address  # the original code in socket.py
# My change here:
if host == "www.google.com":
    host = target_ip  
for res in getaddrinfo(host, port, 0, SOCK_STREAM): # the original code in socket.py

我发现它很好用。

现在我希望主机ip翻译只在这个python程序中工作。

所以我的问题是:当使用import socket时,我如何让我的python程序导入这个socket.py而不是内建的socket.py?

为了说明这一点,这里有一个例子。假设"test"是我的工作目录:

test
|--- main.py
|--- socket.py

在这种情况下:

  1. 如何通过import socket使main.py使用test/socket.py?

  2. 如何让其他模块在使用import socket

我认为更改模块查找路径的顺序可能会有所帮助。但我发现,即使当前路径(''(已经位于sys.path的第一位,并且import socket仍然导入内置的scoket模块。

在导入任何其他可能使用它的模块之前,您可以对sys.modules进行猴子补丁,放置自己的模块而不是标准的socket

# myscript.py
from myproject import mysocket
import sys
sys.modules['socket'] = mysocket
# ... the rest of your code
import requests
...

为此,mysocket应该公开标准socket所做的一切。

# mysocket.py
import socket as _std_socket
from socket import *  # expose everything
def create_connection(address, *args, **kwargs):
    if address == ...:
       address = ...
    return _std_socket.create_connection(address, *args, **kwargs)

这可能是对mysocket.py应该是什么样子的过度简化。你可能需要添加一些定义,然后才能在生产中使用,但你已经明白了。


另一种方法是对socket模块本身进行猴子补丁,即覆盖原始模块内的名称。

# myscript.py
import socket
def create_connection2(...):
    ...
socket.create_connection = create_connection2
# ... the rest of your code
import requests
...

我更喜欢前一种方法,因为它更干净,因为你不需要进入模块内部,只需要隐藏它并从外部覆盖其中的一些内容。

您可以使用相对导入在本地使用socket.py模块。但是,要做到这一点,您的项目必须结构化为一个包。

from . import socket

最新更新