2016-06-13 31 views
0

我遇到了一个非常奇怪的问题,那让我怀疑我是否理解异常处理。Python 2.7 - 在finally子句上的奇怪行为

我有一个代码(我将在后结束),看起来或多或少是这样的:

try: 
    doSomething() 
finally: 
    print 'bye' 

finally子句中的代码,当我通过CTRL退出我的程序没有被执行+ C。

更糟糕的是,现在考虑以下因素:

try: 
    doSomething() 
except: # this could be replaced by except Exception, it doesn't matter 
    print 'something' 
finally: 
    print 'bye' 

现在不执行除了子句中的代码..但最后子句中的代码!

我意识到这必须是由doSomething()执行的代码的错误。但我的问题是,怎么可能呢?我认为我们可以100%确信最终条款总是被执行。

这里是真正的代码。它运行在覆盆子pi 3上。它是对代码here的改编。

import RPi.GPIO as GPIO, time 

GPIO.setmode(GPIO.BCM) 

# Define function to measure charge time 
def RCtime (PiPin): 
    # Discharge capacitor 
    GPIO.setup(PiPin, GPIO.OUT) 
    GPIO.output(PiPin, GPIO.LOW) 
    time.sleep(.1) 

    time1 = time.time() 
    GPIO.setup(PiPin, GPIO.IN) 
    if (GPIO.input(PiPin) == GPIO.LOW): 
     GPIO.wait_for_edge(PiPin, GPIO.RISING, timeout=1000) 
    time_elap = time.time()-time1 

    return time_elap*1e3 

# Main program loop 
try: 
    while True: 
     print RCtime(4) # Measure timing using GPIO4 
except Exception: 
    print '---------got ya-----------------' 
finally: 
    print '---Finaly---' 
    GPIO.cleanup() # this ensures a clean exit 

更具体地,所描述的行为,当该程序是在GPIO.wait_for_edge(PiPin, GPIO.RISING, timeout=1000)在线等待出现。

+0

除非尝试失败才会执行。只要程序仍在运行,如果尝试完成或失败,最终将完成。 Crtl-c与sys.exit()相同。抛出异常,但程序终止,因为python退出,所以无法处理该异常。 – TheLazyScripter

+1

@ TheLazyScripter Ctrl-C产生[**'KeyboardInterrupt' **](https://docs.python.org/2/library/exceptions.html#exceptions.KeyboardInterrupt),它可以在异常块中捕获(但不能'Exception Exception'由'KeyboardInterrupt'继承自''BaseException''](https://docs.python.org/2/library/exceptions.html#exceptions.BaseException)而不是'Exception' –

+0

不管我是否捕捉到异常,关键是程序正在终止,并且finally块没有被执行(在第一种情况下),我在问怎么这甚至是可能的, – LGenzelis

回答

0

如果您的代码不处理KeyboardInterrupt异常,系统必须执行此操作:这意味着它会杀死代码。相反,如果你有一个异常处理程序,你的代码会接管,离开循环,然后执行finally块。

+0

关键不在于我是否抓住这个问题的关键在于程序正在终止并且finally块没有被执行(在第一种情况下)我在问这怎么可能 – LGenzelis

+0

由于你没有发现异常,操作系统立即终止你的程序,所以没有机会执行'最后'块。如果你发现了这个例外,不管你是否使用它 - 你已经阻止了操作系统杀死你的代码,所以它可以继续到最后一部分。 – VBB

+0

这不是它的工作原理@VBB。最后应该总是被执行。试试这个python片段: '试试: 1/0 finally: print'Im here anyway' ' – LGenzelis

0

好吧,这似乎是一个与RPi.GPIO处理信号(如KeyboardInterrupt)方式有关的错误。该模块调用c中编写的一些函数。该函数有点像捕获KeyboardInterrupt并引发异常,但它没有正确执行。除了只有一个例外,这两个例外是“堆积”的。因此,我的代码中的异常之后运行的第一件事将由第二个异常终止。如果我不包含except块,finally块将在第一个异常后执行,并由第二个异常终止。如果我包含一个except块,它会尝试在第一个异常之后运行,由于第二个异常而失败,然后它将转到finally块。 我只找到一个forum人们处理类似的问题。

我以前的实验后,我很好奇,它的运作方式 输入()https://svn.python.org/projects/python/trunk/Parser/myreadline.c]。我用raw_input()替换了sem.acquire(),并运行了相同的 测试。现在内部的例外是真正采用的,所以它的工作原理与预期的OP 一样。然而,该例外是KeyboardInterrupt,而不是来自IPC模块的特殊 例外。 所以我查看了源代码他们是如何做到的: 代码位于Parser/myreadline.c中。

这个用于函数输入的代码调用PyErr_CheckSignals()和 PyOS_InterruptOccurred()来正确处理中断。所以它似乎是OP应该做类似的事情。 Onl; y提供自定义 错误,您将不得不做一些其他的事情。我不知道什么,但可能 调用PyErr_SetString就足够了,因为它可能会覆盖KeyboardInterrupt的 东西。