如何在 python 中实现内建函数的重载

最近遇到一个有意思的需求,需要重载 exit 和 sys.exit 这两个函数,希望用户在调用这两个函数时,能有一些操作记录,方便判断;但是又不能直接更改 c 源码后重新编译。

第一个方式是这样实现:

import sys

temp = exit

def myExit(code):
    print("get code to exit ",code)
    temp(code)

exit = myExit
sys.exit = myExit

print("hehe")
exit(1) # sys.exit(1)

初看上面这个没有什么问题,但是它无法解决跨包的问题。假设上面的代码在包 A 中,A 会调用 B 包的接口,而 B 包在必要条件下,会调用 exit 或者 sys.exit 退出进程。如果按照上面的方式来修改,除非在每个包中都重载 exit 或者 sys.exit,否则会造成循环引用。当然还有一个办法是建立一个全局的重载包,在每个独立库中都 import 这个包中的内容;不过一方面这个改动几乎很大,很多包是第三方的,不方便这么操作,另一方面是它只能解决 sys.exit 却不能解决 exit 的重载。而且这个重载一定要在每个包的开头导入,否则可能还没来得及重载退出函数,进程就退出了。

目前找到一个比较有效的方法,不过这需要两个前置条件:

  1. python 在执行具体的入口文件前,可以挂钩子;
  2. python 有自己作用域分层结构,很多直接使用的函数在内建模块中;

python 进程启动前的钩子函数

sitecustomize.py,这是一个独特的文件,一般放在 site-packages 下边,python 每次启动时,在执行指定的脚本前,会先查看有没有这个文件,如果有,就先执行这里边的内容。所以我们可以把相关重载的逻辑放在这个文件中;但是如果按照上面的方式重载 exit ,还是不行,因为此时 exit 只是个文件内的局部变量。需要更改内建级别的才可以。

更改内置函数

我们使用的 float、int、abs 等函数,都没有加模块名,因为这些是内置模块,都在 builtins 中;但是 builtins 这个又有包可以被导入增删查改等。比如我们完全可以像下面这样更改 abs 的定义:

import builtins
def myAbs(num):
	return num - 1
builtins.abs = myAbs

按照上面的方式,则 abs 的含义完全变了。

结合上面两点,我们就可以在不重新编译 python 的情况下,实现 exit 和 sys.exit 的重载了,只要在 site-packages 文件夹下新建 sitecustomize.py 文件,并在其中写入以下代码即可:

import builtins

import sys

temp = builtins.exit

def myExit(code):
    print("get code to exit ",code)
    temp(code)

builtins.exit = myExit
sys.exit = myExit

此时,整个进程的 exit 和 sys.exit 就全部变成了自己想要的。不得不说,python 中这种基于指针/引用的方式还是非常有趣的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值