今天,我们将深入探讨退出/终止 Python 脚本的主题!
您可以使用您选择的 IDE,但这次我将使用 Microsoft 的 Linux Subsystem for Windows (WSL) 软件包。有关该功能以及如何在 Windows 10 上启用它的更多信息,请访问here.
为什么 Python 在脚本完成后会自动退出?
Python 执行代码块的方式使其按顺序执行每一行,检查要导入的依赖关系,读取定义和类以存储在内存中,并按顺序执行代码段,从而允许循环和回调已定义的定义和类。
当 Python 解释器到达文件末尾 (EOF) 时,它会注意到它无法从源读取更多数据,无论是用户通过 IDE 输入的数据还是从文件中读取的数据。为了演示,让我们尝试获取用户输入并在执行过程中中断解释器!
首先,从 PowerShell 中的 bash 终端打开一个名为“input.py”的新文件:
$ nano input.py
然后右键单击 PowerShell 窗口,将以下内容粘贴到 shell 中
name=input("Don't type anything!\n")
print("Hi,",name,"!")
现在,按CTRL+X
要保存并退出 Nano 窗口,请在 shell 中输入:
$ python3 input.py
Don't type anything!
并按CTRL+D
在等待用户输入时终止程序
Traceback (most recent call last):
File "input.py", line 1, in
name=input("Don't type anything!")
EOFError
The EOFError
异常告诉我们,Python 解释器在完成执行代码之前遇到了文件结尾 (EOF) 条件,因为用户没有输入任何输入数据。
当Python同时达到EOF条件时,它已经执行了所有代码而不抛出任何异常,这是Python可以“优雅”退出的一种方式。
检测脚本退出
如果我们想知道Python程序何时退出而不抛出异常,我们可以使用内置的Pythonatexit
module.
Theatexit
处理我们希望程序退出时执行的任何操作,通常用于在程序进程终止之前进行程序清理
为了试验 atexit,让我们修改 input.py 示例以在程序退出时打印一条消息。再次打开 input.py 文件并将文本替换为此
import atexit
atexit.register(print,"Program exited successfully!")
name=input("What's your name?\n")
print("Hi,",name,"!")
输入你的名字,当你按回车键时,你应该得到:
What's your name?
Example
Hi, Example !
Program exited successfully!
请注意退出文本如何出现在输出的末尾,无论我们将其放置在何处atexit
调用,以及如果我们替换atexit
调用一个简单的print()
,我们得到退出文本,其中print()
一切都是在代码退出的地方完成的。
Program exited successfully!
What's your name?
Example
Hi, Example !
优雅退出
有多种方法可以退出 Python 程序,但不涉及抛出异常;第一个要尝试的是quit()
您可以使用 bash 命令echo $?
获取Python解释器的退出代码。
$ python3
Python 3.8.2 (default, Apr 1 2020, 15:52:55)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> quit()
$ echo $?
0
我们还可以通过以下方式定义解释器应该退出的代码类型quit()
小于 256 的整数参数
$ python3
Python 3.8.2 (default, Apr 1 2020, 15:52:55)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> quit(101)
$ echo $?
101
exit()
与它的别名具有相同的功能quit()
$ python3
Python 3.8.2 (default, Apr 1 2020, 15:52:55)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> exit(101)
$ echo $?
101
Neither quit()
nor exit()
被认为是好的做法,因为它们都需要网站模块,它旨在用于交互式解释器而不是在程序中。对于我们的程序,我们应该使用类似的东西sys.exit
$ python3
Python 3.8.2 (default, Apr 1 2020, 15:52:55)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.exit(101)
$ echo $?
101
请注意,我们需要显式导入一个模块来调用exit()
,这可能看起来不是一个改进,但它保证了必要的模块被加载,因为这不是一个好的假设site
将在运行时加载。如果我们不想导入额外的模块,我们可以做什么exit()
, quit()
and sys.exit()
正在幕后做着raise SystemExit
$ python3
Python 3.8.2 (default, Apr 1 2020, 15:52:55)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> raise SystemExit(101)
$ echo $?
101
退出并显示错误消息
如果我们从用户那里得到错误的输入怎么办?让我们回顾一下我们的input.py
脚本,并添加处理用户错误输入的能力(CTRL+D
传递 EOF 字符)
$ nano input.py
try:
name=input("What's your name?\n")
print("Hi, "+name+"!")
except EOFError:
print("EOFError: You didn't enter anything!")
$ python3 input.py
What's your name?
EOFError: You didn't enter anything!
The try
语句告诉Python尝试语句内的代码并将任何异常传递给except
退出前的声明。
退出没有错误
如果用户向您的程序发出错误,但您不希望代码打印错误或进行某种错误处理以最大程度地减少对用户的影响,该怎么办?
我们可以添加一个finally
语句让我们在执行错误处理后执行代码catch
$ nano input.py
try:
name=input("What's your name?\n")
if(name==''):
print("Name cannot be blank!")
except EOFError:
#print("EOFError: You didn't enter anything!")
name="Blankname"
finally:
print("Hi, "+name+"!")
$ python3 input.py
What's your name?
Hi, Blankname!
请注意,用户永远不会知道EOFError
发生时,这可用于在输入或参数不良时传递默认值。
退出并释放资源
一般来说,Python 在程序退出时会自动释放您在程序中调用的所有资源,但对于某些进程,最好将一些有限的资源封装在一个进程中。with
block.
通常你会看到这个open()
调用,如果未能正确释放文件可能会导致稍后读取或写入文件时出现问题。
$ nano openfile.py
with open("testfile.txt","w") as file:
file.write("let's write some text!\n")
$ python3 openfile.py
$ cat testfile.txt
let's write some text!
The with
块自动释放其内请求的所有资源。如果我们想更明确地确保文件已关闭,我们可以使用atexit.register()
呼叫命令close()
$ nano openfile.py
import atexit
file=open("testfile.txt","w")
file.write("let's write some text!\n")
atexit.register(file.close)
如果调用资源时不使用with
块,确保在一个atexit
命令。
一段时间后退出
如果我们担心我们的程序可能永远不会正常终止,那么我们可以使用Python的multiprocessing
模块以确保我们的程序将终止。
$ nano waiting.py
import time
import sys
from multiprocessing import Process
integer=sys.argv[1]
init=map(int, integer.strip('[]'))
num=list(init)[0]
def exclaim(int):
time.sleep(int)
print("You were very patient!")
if __name__ == '__main__':
program = Process(target=exclaim, args=(num,))
program.start()
program.join(timeout=5)
program.terminate()
$ python3 waiting.py 7
$ python3 waiting.py 0
You were very patient!
请注意,当函数被告知等待 7 秒时,进程无法完成,但当函数被告知等待 0 秒时,进程却完成并打印了它应该执行的操作!
使用 return 语句退出
如果我们有一段代码,我们想用它来终止整个程序,而不是让break
语句在循环外继续代码,我们可以使用return sys.exit()
完全退出代码。
$ nano break.py
import time
import sys
def stop(isTrue):
for a in range(0,1):
if isTrue:
break
else:
print("You didn't want to break!")
return sys.exit()
mybool = False
stop(mybool)
print("You used break!")
在函数中间退出
如果我们不想使用 return 语句,我们仍然可以调用sys.exit()
结束我们的计划并提供return
在另一个分支。让我们再次使用break.py 中的代码。
$ nano break.py
import time
import sys
def stop(isTrue):
for a in range(0,1):
if isTrue:
word="bird"
break
else:
print("You didn't want to break!")
sys.exit()
mybool = False
print(stop(mybool))
满足条件时退出
如果我们的 Python 代码中有一个循环,并且我们希望确保代码在遇到问题时可以退出,我们可以使用一个可以检查的标志来终止程序。
$ nano break.py
import time
import sys
myflag=False
def stop(val):
global myflag
while 1==1:
val=val+1
print(val)
if val%5==0:
myflag=True
if val%7==0:
myflag=True
if myflag:
sys.exit()
stop(1)
$ python3 break.py
2
3
4
5
按键退出
如果我们想让程序在控制台中保持打开状态直到按下某个键,我们可以使用未绑定的input()
关闭它。
$ nano holdopen.py
input("Press enter to continue")
$ python3 holdopen.py
Press enter to continue
$
我们还可以通过CTRL+C
到控制台给Python一个KeyboardInterrupt
特点。我们甚至可以处理KeyboardInterrupt
就像我们之前处理异常一样。
$ nano wait.py
import time
try:
i=0
while 1==1:
i=i+1
print(i)
time.sleep(1)
except KeyboardInterrupt:
print("\nWhoops I took too long")
raise SystemExit
$ python3 wait.py
1
2
3
^C
Whoops I took too long
退出多线程程序
退出多线程程序稍微复杂一些,作为一个简单的sys.exit()
从只会退出当前线程的线程调用。 “肮脏”的方法是使用os._exit()
$ nano threads.py
import threading
import os
import sys
import time
integer=sys.argv[1]
init=map(int, integer.strip('[]'))
num=list(init)[0]
def exclaim(int):
time.sleep(int)
os._exit(1)
print("You were very patient!")
if __name__ == '__main__':
program = threading.Thread(target=exclaim, args=(num,))
program.start()
program.join()
print("This should print before the main thread terminates!")
$ python3 threads.py 6
$
正如你所看到的,程序在退出之前并没有打印程序的其余部分,这就是为什么os._exit()
通常保留作为最后手段,并调用Thread.join()
从主线程退出是结束多线程程序的首选方法。
$ nano threads.py
import threading
import os
import sys
import time
import atexit
integer=sys.argv[1]
init=map(int, integer.strip('[]'))
num=list(init)[0]
atexit.register(print,"Threads exited successfully!")
def exclaim(int):
time.sleep(int)
print("You were very patient!")
if __name__ == '__main__':
program = threading.Thread(target=exclaim, args=(num,))
program.start()
program.join()
$ python3 threads.py 6
You were very patient!
Threads exited successfully!
结束但不退出 sys
Sys.exit()
这只是我们退出 Python 程序的几种方法之一,什么sys.exit()
确实是raise SystemExit
,因此我们可以轻松地使用任何内置的 Python 异常或创建我们自己的异常!
$ nano myexception.py
class MyException(Exception):
pass
try:
raise MyException()
except MyException:
print("The exception works!")
$ python3 myexception.py
The exception works!
我们还可以使用os._exit()
告诉主机系统杀死 python 进程,尽管这不起作用atexit
清理。
$ python3
Python 3.8.2 (default, Apr 1 2020, 15:52:55)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os._exit(1)
异常退出
如果我们想在任何异常情况下退出而不进行任何处理,我们可以使用我们的try-except
块执行os._exit()
.
注意:这也会捕获任何sys.exit()
, quit()
, exit()
, or raise SystemExit
调用,因为它们都会生成SystemExit
例外。
$ python3
Python 3.8.2 (default, Apr 1 2020, 15:52:55)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> try:
... quit()
... except:
... os._exit(1)
...
$ echo $?
1
退出并重新启动
最后,我们将探讨如何退出 Python 并重新启动程序,这在许多情况下很有用。
$ nano restart.py
import atexit
import os
atexit.register(os.system,"python3 restart.py")
try:
n=0
while 1==1:
n=n+1
if n%5==0:
raise SystemExit
except:
print("Exception raised!")
$ python3 restart.py
Exception raised!
Exception raised!
...
Exception raised!
^Z
[3]+ Stopped python3 restart.py
我希望您觉得本教程有用。继续回来。
谢谢。