在Python 3.4中调用子进程并处理无效命令的错误?

3 投票
2 回答
1342 浏览
提问于 2025-04-18 15:11

我正在尝试在Python 3.4中执行一个外部程序。当我的“命令”写错了时,程序就会崩溃。有什么办法可以优雅地处理这些错误,并让程序恢复过来吗?

    # Call a system process
    try:
        pipe = subprocess.Popen(command,
                                stdout=subprocess.PIPE)
    except (OSError,
            subprocess.CalledProcessError) as error:
        print("Failed to execute command")
        print(command)
        print("Error: " + error.output)

    while True:
        output = pipe.stdout.readline()
        if not output:
            print("Finished...")
            break

        output = output.decode()
        output = output.strip("\r")
        output = output.strip("\n")
        print(output)

当我调用一个无效的命令时,程序会崩溃,像这样:

C:\SDKs\Python34\python.exe C:\Users\user\Documents\GitHub\PyQtApps\QtDeploy\src\main.py
Traceback (most recent call last):
Executing:  windeployqt.exe  C:\Users\user\Documents\GitHub\SpaCentralSoftBin\GUIController.exe
  File "C:\Users\user\Documents\GitHub\PyQtApps\QtDeploy\src\forms\maindialog.py", line 81, in execute_windeployqt
Failed to execute command
    stdout=subprocess.PIPE)
windeployqt.exe  C:\Users\user\Documents\GitHub\SpaCentralSoftBin\GUIController.exe
  File "C:\SDKs\Python34\lib\subprocess.py", line 858, in __init__
    restore_signals, start_new_session)
  File "C:\SDKs\Python34\lib\subprocess.py", line 1111, in _execute_child
    startupinfo)
FileNotFoundError: [WinError 2] The system cannot find the file specified

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\user\Documents\GitHub\PyQtApps\QtDeploy\src\forms\maindialog.py", line 159, in on_buttonBox_clicked
    self.execute_windeployqt()
  File "C:\Users\user\Documents\GitHub\PyQtApps\QtDeploy\src\forms\maindialog.py", line 86, in execute_windeployqt
    print("Error: " + error.output)
AttributeError: 'FileNotFoundError' object has no attribute 'output'

2 个回答

1
FileNotFoundError' object has no attribute 'output'

使用

print("Error: " + error)

FileNotFoundErrr 有一些可能会对你有用的属性:

 args
 characters_written
 errno
 filename
 filename2
2

更大的问题是,打印错误信息并不能真正“处理”错误,虽然很多人认为这样做是有效的。

如果你想记录一个错误信息,那就记录吧,然后退出你的程序。实际上,能够处理错误的情况很少,比如说如果一个配置文件无法读取,你可以尝试读取一个全局的配置文件,或者把KeyboardInterrupt传递给一个主循环,这个主循环在读取命令。

在你的例子中,如果你在except块里没有出错,output = pipe.stdout...会导致:

NameError: name 'pipe' is not defined

即使你捕获了这个错误,仍然没有什么有效的方法来恢复你的代码所期望的状态。而且,你还会把你得到的错误追踪信息移动到一个没有错误的地方。

在这种情况下,一个好的做法是

except SomeError:
    log what you want
    raise

这里一个空的raise会重新抛出最后一个异常,这样会向上传播,形成一个完整的错误追踪信息,这样你就能更清楚地知道错误出在哪里。如果你不这样做,你就会丢失有用的信息。

撰写回答