如何重载Python内置模块?
我想在我的Python程序中把主机绑定到指定的IP地址。我的目标是只在这个程序里生效,所以我不打算修改 /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程序中有效。
所以我的问题是:我该如何让我的Python程序在使用 import socket
时导入这个自定义的socket.py,而不是内置的那个?
为了更清楚,这里有个例子。假设 'test' 是我的工作目录:
test
|--- main.py
|--- socket.py
在这种情况下:
我该如何让 main.py 使用 test/socket.py,通过
import socket
?我该如何让其他模块在使用
import socket
时也使用 test/socket.py?
我觉得改变模块查找路径的顺序可能有帮助。但我发现即使当前路径(''
)已经在 sys.path
的第一位,使用 import socket
仍然会导入内置的socket模块。
2 个回答
你可以使用相对导入来在本地使用一个叫做socket.py的模块。不过,要做到这一点,你的项目必须按照包的结构来组织。
from . import socket
你可以通过修改 sys.modules
,在导入任何可能使用标准 socket
的模块之前,把自己的模块放进去,替代掉标准的 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
...
我更喜欢前一种方法,因为这样更干净,你不需要去 内部 修改模块,只需在外部隐藏并覆盖其中的一些内容。