为什么 exit() 无法退出程序?

这是「进击的Coder」的第 481 篇技术分享

作者:kingname

来源:未闻 Code

阅读本文大概需要 4 分钟。

我们在 Python 交互环境的里面,可能会使用exit()来退出程序,例如:

453bb62dbee18ded65d15a2b8554fe84.png

有时候,当我们想让 Python 程序在遇到某些条件的时候退出,也可以使用exit(),如下图所示:

def run(options):
    if options == '1':
        print('执行逻辑1')
    elif options == '2':
        print('执行逻辑2')
    elif options == 'exit':
        print('退出程序!')
        exit()
    else:
        print('只能输入1,2或者exit')

while True:
    option = input('请输入选项:')
    run(option)
a8162f5a3df8c1643baeeb3b3308178c.png

但有时候,你会发现exit()似乎出了一些问题。执行它以后,程序虽然确实也会结束,但是它会报错。例如下面这段代码:

def run(options):
    if options == '1':
        print('执行逻辑1')
    elif options == '2':
        print('执行逻辑2')
    elif options == 'exit':
        print('退出程序!')
        exit()
    else:
        print('只能输入1,2或者exit')

while True:
    option = input('请输入选项:')
    try:
        run(option)
    except:
        pass

运行效果如下图所示:

326b1ea1cdf434068cf91fbf2ab27b08.png

还有一些时候,exit()甚至直接失效,例如:

def func(param):
    def wrap(args):
        try:
            print(args)
            exit()
        except:
            pass
    wrap(param)

for i in range(10):
    func(i)

运行效果如下图所示。

b9c96bfc986dbd2baff04e2495e4d88e.png

要解释这个问题,我们就要先来搞清楚,在 Python 里面,退出当前程序的几个命令:exit()quit()sys.exit()os._exit()有什么区别和联系。

实际上,exit()quit()sys.exit(),他们背后的原理都是一样的,都是在执行的时候,抛出一个异常raise SystemExit。所以,我们甚至可以直接在代码里面手动抛出这个异常来退出程序:

54d409f427276a60edc9e46f220da3f7.png

在正常情况下,无论你是执行这三个命令,还是手动抛出SystemExit异常,Python 解释器都能检查到这个异常,然后清理当前进程占用的各个句柄和缓存 buffer。

但问题在于,SystemExit是基于BaseException实现的一个异常,所以当你的代码里面使用try...except...的时候,你会捕获到这个异常。但是在except里面,你又直接pass了,所以就什么也做不到。于是程序就无法正常退出了。

如果你非要使用try ... except ...其实也很简单,你使用具体的某个异常,或者直接使用Exception。这样一来,由于SystemExit不是基于Exception的,所以就不会被捕获。捕获了Exception以后,代码运行效果如下图所示:

128d2fbd8c35aabcf04d71244ead16cc.png

从图中可以看到,程序打印了第一个数字就正常退出了。

上面的问题解决了,可能还有人会问,这四个退出方法有什么区别呢?其实exit()quit()完全一样,就是方便有些人习惯用exit这个词,有些人习惯用quit()这个词。一般来说,当你在Python互换环境里面,可以使用这两个函数的任何一个来退出。

sys.exit()需要提前导入sys模块。所以一般在.py项目代码里面使用。因为可能有些系统的Python环境,没有exit()quit()函数,但肯定有sys模块。

而至于os._exit()这个函数,它可以立刻结束当前进程,不会清理句柄,也不会清理缓存buffer。就相当于kill -9 进程ID

cc1ce92404795b525b07b449a5d5ae2d.png

End

「进击的Coder」专属学习群已正式成立,搜索「CQCcqc4」添加崔庆才的个人微信或者扫描下方二维码拉您入群交流学习。

d4b409f02cff154550eb3501d7aef8fd.png

看完记得关注@进击的Coder

及时收看更多好文

↓↓↓

崔庆才的「进击的Coder」知识星球已正式成立,感兴趣的可以查看《我创办了一个知识星球》了解更多内容,欢迎您的加入:

d7cd5f12a8025b551b8a469f443526aa.png

好文和朋友一起看~

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值