如何在python中重载内置模块?

WKP*_*lus 5 python sockets

我正在尝试将主机绑定到我的python程序中的指定ips。只需使其在python程序中起作用即可,因此我将不修改该/etc/hosts文件。

我试图在该create_connection函数中添加一些代码以socket.py进行主机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
Run Code Online (Sandbox Code Playgroud)

我发现它工作正常。

现在,我希望host-ip转换仅在此python程序中有效。

所以我的问题是:使用时,如何使我的python程序导入此socket.py而不是内置的import socket

为了清楚起见,这是一个示例。假设“ test”是我的工作目录:

test
|--- main.py
|--- socket.py
Run Code Online (Sandbox Code Playgroud)

在这种情况下:

  1. 我怎样才能使main.py使用test / socket.py import socket

  2. 如何在使用其他模块时使用test / socket.py import socket

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

shx*_*hx2 5

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

# myscript.py

from myproject import mysocket
import sys
sys.modules['socket'] = mysocket

# ... the rest of your code
import requests
...
Run Code Online (Sandbox Code Playgroud)

为此,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)
Run Code Online (Sandbox Code Playgroud)

这可能是对mysocket.py应该是什么样子的过度简化。在将其用于生产之前,您可能需要添加一些定义,但您明白了。


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

# myscript.py
import socket

def create_connection2(...):
    ...

socket.create_connection = create_connection2

# ... the rest of your code
import requests
...
Run Code Online (Sandbox Code Playgroud)

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