如何终止脚本?

如何提前退出脚本,例如PHP中的die()命令?

1931461 次浏览
import syssys.exit()

来自#0模块留档的详细信息:

sys.exit([arg])

退出Python。这是通过提高#0异常,所以清理操作指定的最后子句#0语句中的一个被尊重,并且可以拦截在外部级别退出尝试。

可选参数arg可以是一个整数,给出退出状态(默认为零)或其他类型的对象。如果它是整数,零被认为是“成功终止”,任何非零值都是被贝壳等视为“异常终止”。大多数系统要求它在0-127范围内,并产生未定义的结果有些系统有一个约定来分配特定的特定退出代码的含义,但这些通常是不发达;Unix程序通常使用2作为命令行语法错误和1为所有其他类型的错误。如果另一种类型的对象则无等价于传递零,并且任何其他对象都是打印到#0并导致退出代码为1。特别是,sys.exit("some error message")是一种快速退出程序的方法发生错误。

由于#0最终“仅”引发异常,因此它只会退出从主线程调用时的进程,异常不是截获

下面的@糖化矩阵指出,如果你想要一个“硬退出”,你可以使用os._exit(*errorcode*),尽管它在某种程度上可能是os特定的(例如,它可能不会在windows下接受错误代码),而且它肯定不那么友好,因为它不会让解释器在进程死亡之前进行任何清理。另一方面,它确实杀死整个进程,包括所有正在运行的线程,而sys.exit()(正如它在文档中所说)只有在从主线程调用时才退出,而没有其他线程运行。

另一种方法是:

raise SystemExit
from sys import exitexit()

作为参数,您可以传递退出代码,该代码将返回给操作系统。默认值为0。

虽然您通常应该更喜欢sys.exit,因为它对其他代码更“友好”,但它实际上所做的只是引发异常。

如果您确定需要立即退出一个进程,并且您可能在某个异常处理程序中,它会捕获SystemExit,那么还有另一个函数-os._exit-它会在C级别立即终止,并且不执行任何正常的解释器拆除;例如,注册到“atexit”模块的钩子不会被执行。

提前终止Python脚本的一个简单方法是使用内置的quit()函数。不需要导入任何库,而且高效简单。

示例:

#do stuffif this == that:quit()

您也可以简单地使用exit()

请记住,sys.exit()exit()quit()os._exit(0)杀死是Python解释器。因此,如果它出现在execfile()从另一个脚本调用的脚本中,它会停止两个脚本的执行。

请参阅“停止执行用执行文件调用的脚本”以避免这种情况。

我是一个完全的新手,但肯定这是更清洁,更可控

def main():try:Answer = 1/0print  Answerexcept:print 'Program terminated'returnprint 'You wont see this'
if __name__ == '__main__':main()

程序终止

import sysdef main():try:Answer = 1/0print  Answerexcept:print 'Program terminated'sys.exit()print 'You wont see this'
if __name__ == '__main__':main()

程序终止回溯(最近一次调用):文件“Z:\Directory\testdieprogram.py”,第12行,在main()文件“Z:\Directory\testdieprogram.py”,第8行,在main中sys.exitSystemExit

编辑

关键是程序平稳和平地结束,而不是“我停了!!!!”

我刚刚发现,在编写多线程应用程序时,raise SystemExitsys.exit()都只杀死正在运行的线程。另一方面,os._exit()退出整个进程。这在“为什么sys.exit()在Python中的线程内调用时不退出?”中讨论过。

下面的示例有2个线程。Kenny和Cartman。Cartman应该永生,但Kenny被递归调用,应该在3秒后死亡。(递归调用不是最好的方法,但我有其他原因)

如果我们也想让卡特曼在肯尼死后死去,肯尼应该带着0号离开,否则,只有肯尼会死,卡特曼会永远活着。

import threadingimport timeimport sysimport os
def kenny(num=0):if num > 3:# print("Kenny dies now...")# raise SystemExit #Kenny will die, but Cartman will live forever# sys.exit(1) #Same as above
print("Kenny dies and also kills Cartman!")os._exit(1)while True:print("Kenny lives: {0}".format(num))time.sleep(1)num += 1kenny(num)
def cartman():i = 0while True:print("Cartman lives: {0}".format(i))i += 1time.sleep(1)
if __name__ == '__main__':daemon_kenny = threading.Thread(name='kenny', target=kenny)daemon_cartman = threading.Thread(name='cartman', target=cartman)daemon_kenny.setDaemon(True)daemon_cartman.setDaemon(True)
daemon_kenny.start()daemon_cartman.start()daemon_kenny.join()daemon_cartman.join()

在Python 3.5中,我尝试在不使用模块(例如sys、Biopy)的情况下合并类似的代码,而不是内置的停止脚本并向我的用户打印错误消息的模块。这是我的例子:

## My example:if "ATG" in my_DNA:## <Do something & proceed...>else:print("Start codon is missing! Check your DNA sequence!")exit() ## as most folks said above

后来,我发现直接抛出一个错误会更简洁:

## My example revised:if "ATG" in my_DNA:## <Do something & proceed...>else:raise ValueError("Start codon is missing! Check your DNA sequence!")

我的两分钱。

Python 3.8.1,Windows 10,64位。

sys.exit()不直接为我工作。

我有几个nexted循环。

首先我声明一个布尔变量,我称之为immediateExit

所以,在程序代码的开头,我写:

immediateExit = False

然后,从最内部(嵌套)循环异常开始,我写:

            immediateExit = Truesys.exit('CSV file corrupted 0.')

然后我进入外部循环的直接延续,在代码执行任何其他内容之前,我写:

    if immediateExit:sys.exit('CSV file corrupted 1.')

根据复杂性,有时上述语句也需要在除了部分等中重复。

    if immediateExit:sys.exit('CSV file corrupted 1.5.')

自定义消息也用于我的个人调试,因为这些数字是出于相同的目的-查看脚本真正退出的位置。

'CSV file corrupted 1.5.'

在我的特殊情况下,我正在处理一个CSV文件,如果软件检测到它已损坏,我不希望软件触摸它。因此,对我来说,在检测到可能的损坏后立即退出整个Python脚本非常重要。

随着所有循环的逐渐sys.exit,我设法做到了。

完整代码:(需要进行一些更改,因为它是内部任务的专有代码):

immediateExit = Falsestart_date = '1994.01.01'end_date = '1994.01.04'resumedDate = end_date

end_date_in_working_days = Falsewhile not end_date_in_working_days:try:end_day_position = working_days.index(end_date)
end_date_in_working_days = Trueexcept ValueError: # try statement from end_date in workdays checkprint(current_date_and_time())end_date = input('>> {} is not in the list of working days. Change the date (YYYY.MM.DD): '.format(end_date))print('New end date: ', end_date, '\n')continue

csv_filename = 'test.csv'csv_headers = 'date,rate,brand\n' # not real headers, this is just for exampletry:with open(csv_filename, 'r') as file:print('***\nOld file {} found. Resuming the file by re-processing the last date lines.\nThey shall be deleted and re-processed.\n***\n'.format(csv_filename))last_line = file.readlines()[-1]start_date = last_line.split(',')[0] # assigning the start date to be the last like date.resumedDate = start_date
if last_line == csv_headers:passelif start_date not in working_days:print('***\n\n{} file might be corrupted. Erase or edit the file to continue.\n***'.format(csv_filename))immediateExit = Truesys.exit('CSV file corrupted 0.')else:start_date = last_line.split(',')[0] # assigning the start date to be the last like date.print('\nLast date:', start_date)file.seek(0) # setting the cursor at the beginnning of the filelines = file.readlines() # reading the file contents into a listcount = 0 # nr. of lines with last datefor line in lines: #cycling through the lines of the fileif line.split(',')[0] == start_date: # cycle for counting the lines with last date in it.count = count + 1if immediateExit:sys.exit('CSV file corrupted 1.')for iter in range(count): # removing the lines with last datelines.pop()print('\n{} lines removed from date: {} in {} file'.format(count, start_date, csv_filename))


if immediateExit:sys.exit('CSV file corrupted 1.2.')with open(csv_filename, 'w') as file:print('\nFile', csv_filename, 'open for writing')file.writelines(lines)
print('\nRemoving', count, 'lines from', csv_filename)
fileExists = True
except:if immediateExit:sys.exit('CSV file corrupted 1.5.')with open(csv_filename, 'w') as file:file.write(csv_headers)fileExists = Falseif immediateExit:sys.exit('CSV file corrupted 2.')

问题

在我的实践中,甚至有一种情况需要从其中一个进程中杀死整个多处理器应用程序。

如果您的应用程序使用唯一的主进程,以下函数可以正常工作。但在我的情况下,以下函数中没有一个不起作用,因为应用程序有许多其他活动进程。

  • quit()
  • exit(0)
  • os._exit(0)
  • sys.exit(0)
  • os.kill(os.getppid(), 9)-其中os.getppid()是父进程的pid

最后一个杀死了主进程和它自己,但其余的进程仍然活着。

解决方案

我不得不通过外部命令杀死它,最后使用pkill找到了解决方案。

import os
# This can be called even in process worker and will kill# whole application included correlated processes as wellos.system(f"pkill -f {os.path.basename(__file__)}")

只需放在代码quit()的末尾,就应该关闭一个python脚本。

在Python 3.9中,您还可以使用:raise SystemExit("Because I said so")