我不确定为什么在finally语句中需要try...except...finally。我认为,此代码块

try:
    run_code1()
except TypeError:
    run_code2()
other_code()


与使用finally的代码块相同:

try:
    run_code1()
except TypeError:
    run_code2()
finally:
    other_code()


我想念什么吗?

#1 楼

如果您提早返回,则会有所不同:

try:
    run_code1()
except TypeError:
    run_code2()
    return None   # The finally block is run before the method returns
finally:
    other_code()


与此相比:

try:
    run_code1()
except TypeError:
    run_code2()
    return None   

other_code()  # This doesn't get run if there's an exception.


其他情况可能导致差异:


如果在except块内引发了异常。
如果在run_code1()中引发了异常,但不是TypeError
其他控制流程语句,例如continuebreak语句。


评论


尝试:#x = Hello + 20 x = 10 + 20除外:打印'我在其他块中'x = 20 + 30其他:打印'我在其他块中'x + = 1最后:打印'最后x =% s'%(x)

–阿比吉特·萨胡(Abhijit Sahu)
17-10-2在6:32

#2 楼

您可以使用finally来确保关闭或释放文件或资源,而不管是否发生异常,即使您没有捕获到该异常也是如此。 (或者,如果您没有捕获到该特定异常。)

myfile = open("test.txt", "w")

try:
    myfile.write("the Answer is: ")
    myfile.write(42)   # raises TypeError, which will be propagated to caller
finally:
    myfile.close()     # will be executed before TypeError is propagated


在本示例中,最好使用with语句,但是这种结构可以

几年后,我写了一篇有关滥用finally的博客文章,读者可能会发现这很有趣。

#3 楼

它们不相等。不管其他什么情况发生,最终代码都会运行。这对于必须运行的清除代码很有用。

评论


不管发生什么其他事情,最终代码都会运行...除非存在无限循环。或断电。或os._exit()。要么...

–马克·拜尔斯
2012年7月18日在23:49



@Mark实际上,sys.exit会引发一个正常的异常。但是,是的,任何导致进程立即终止的事物都意味着没有其他执行。

–锑
2012年7月18日在23:52

@锑:谢谢。更改为os._exit。

–马克·拜尔斯
2012年7月18日23:53



只是想知道,为什么不能将清除代码放到除非如果发现例外就进入代码的情况下,否则就不能放在其中?

–斯蒂芬·雅各布
19年2月20日在6:45

@Stephen一方面,即使您从try块返回,代码也最终会运行。在这种情况下,您将不会点击except子句。

–锑
19年2月20日在7:43

#4 楼

要添加到上面的其他答案中,无论执行什么操作都执行finally子句,而仅当未引发异常时才执行else子句。例如,写入没有异常的文件将输出以下内容:

file = open('test.txt', 'w')

try:
    file.write("Testing.")
    print("Writing to file.")
except IOError:
    print("Could not write to file.")
else:
    print("Write successful.")
finally:
    file.close()
    print("File closed.")


输出:

Writing to file.
Write successful.
File closed.


如果有异常,代码将输出以下内容, (请注意,故意使该文件保持只读状态会导致错误。

file = open('test.txt', 'r')

try:
    file.write("Testing.")
    print("Writing to file.")
except IOError:
    print("Could not write to file.")
else:
    print("Write successful.")
finally:
    file.close()
    print("File closed.")


输出:

Could not write to file.
File closed.


我们可以看到finally子句无论出现异常都会执行,希望对您有所帮助。

评论


即使您没有使用“ finally”子句也无法解决问题,因为OP想要知道两者之间的区别,这还是可行的,一个很好的例子会引起与IOError不同的错误,以表明在将异常传播到调用者之前,将执行finally子句块。

– Reda Drissi
19年3月7日在15:13

我不知道还有其他事。有用的知道。

– mazunki
19年11月5日在9:31

#5 楼

代码块不是等效的。如果finally引发了run_code1()之外的异常,或者TypeError引发了异常,则run_code2()子句也将运行,而在这种情况下,第一版other_code()不会运行。

#6 楼

如文档中所述,finally子句旨在定义必须在所有情况下都必须执行的清除操作。


如果存在finally,则它指定“清除”处理程序。执行try
子句,包括任何exceptelse子句。如果在任何子句中发生了
异常并且未对其进行处理,则将临时保存
异常。执行finally子句。如果
有一个已保存的异常,它将在finally

示例:

>>> def divide(x, y):
...     try:
...         result = x / y
...     except ZeroDivisionError:
...         print("division by zero!")
...     else:
...         print("result is", result)
...     finally:
...         print("executing finally clause")
...
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'


如您所见,在任何情况下都执行finally子句。通过划分两个字符串引发的TypeError不会由except子句处理,因此在执行finally子句后会重新引发。

在现实世界的应用程序中,finally子句对于释放外部资源很有用(例如文件或网络连接),无论资源使用是否成功。

#7 楼

在您的第一个示例中,如果run_code1()引发了不是TypeError的异常,会发生什么? ... other_code()将不会执行。

finally:版本进行比较:保证other_code()都将被执行,而不会引发任何异常。

#8 楼

finally用于定义“清理操作”。无论是否发生异常(即使您不处理),在离开finally语句之前,无论如何都将执行try子句。

第二个@Byers的例子。

#9 楼

完美的例子如下:

try:
    #x = Hello + 20
    x = 10 + 20 
except:
    print 'I am in except block'
    x = 20 + 30
else:
    print 'I am in else block'
    x += 1
finally:
    print 'Finally x = %s' %(x)


#10 楼

当您要在运行主要工作的代码之前运行“可选”代码并且可选代码可能由于各种原因而失败时,也可以使用final。

在以下示例中,我们不知道确切地说,store_some_debug_info可能会抛出什么样的异常。

我们可以运行:

try:
  store_some_debug_info()
except Exception:
  pass
do_something_really_important() 


但是,大多数短毛猫会抱怨捕捉到的模糊性太强例外。另外,由于我们选择的只是pass的错误,因此except块并没有真正增加价值。

try:
  store_some_debug_info()
finally:
  do_something_really_important()     


上面的代码与第一个代码具有相同的作用。代码块,但更简洁。

#11 楼

几年来专业地使用delphi教会了我维护最终使用的清理例程。 Delphi几乎强制使用finally来清理在try块之前创建的所有资源,以免引起内存泄漏。这也是Java,Python和Ruby的工作方式。

resource = create_resource
try:
  use resource
finally:
  resource.cleanup


无论尝试和最终之间的操作如何,资源都会被清理。另外,如果执行从未达到try块,也不会清除它。 (即create_resource本身会引发异常),这会使您的代码“异常安全”。

关于为什么您实际上需要一个finally块的原因,并非所有语言都可以。在C ++中,您自动调用了析构函数,这些析构函数在异常展开堆栈时强制执行清除。与尝试...最终语言相比,我认为这是朝着更干净的代码的方向迈进的一步。

{    
  type object1;
  smart_pointer<type> object1(new type());
} // destructors are automagically called here in LIFO order so no finally required.


#12 楼

try块只有一个强制性子句:try语句。
except,else和finally子句是可选的,并且基于用户的偏好。

最后:
Python离开try语句,它将在任何情况下在finally块中运行代码,即使它正在结束程序。例如,如果Python在except或else块中运行代码时遇到错误,则在停止程序之前仍将执行finally块。

评论


错了例外声明是强制性的。 – Lucas Azevedo 2月1日,12:04这是错误的,因为我刚刚编译并运行了带有try-finally块且没有“ except”子句的Python 3.5程序。

–丝束
19年4月11日在20:40



我本人尝试过,但我不敢相信,except子句不是强制性的。

–captainblack
19年6月3日在1:19

#13 楼

运行以下Python3代码以查看最终需求:

情况1:

count = 0
while True:
    count += 1
    if count > 3:
        break
    else:
        try:
            x = int(input("Enter your lock number here: "))

            if x == 586:
                print("Your lock has unlocked :)")

                break
            else:
                print("Try again!!")

                continue

        except:
            print("Invalid entry!!")
        finally:
            print("Your Attempts: {}".format(count))


情况2:

count = 0

while True:
    count += 1
    if count > 3:
        break
    else:
        try:
            x = int(input("Enter your lock number here: "))

            if x == 586:
                print("Your lock has unlocked :)")

                break
            else:
                print("Try again!!")

                continue

        except:
            print("Invalid entry!!")

        print("Your Attempts: {}".format(count))


每次尝试以下输入:


随机整数
正确的代码是586(尝试此操作,您将得到答案)
随机字符串

**在学习Python的早期阶段。

#14 楼

我试图在要阅读Excel工作表的地方运行代码。问题是,如果有一个没有工作表的文件说:SheetSum我无法将其移动到错误位置!我写的代码是:

def read_file(data_file):
    # data_file = '\rr\ex.xlsx'
    sheets = {}
    try:
        print("Reading file: "+data_file)
        sheets['df_1'] = pd.read_excel(open(data_file,'rb'), 'SheetSum')
    except Exception as excpt:
        print("Exception occurred", exc_info=True)
    return sheets

read_file(file)
shutil.move( file, dirpath +'\processed_files')


给予错误:


[WinError 32]该进程无法访问文件,因为它是被另一个进程使用



我必须添加完整的try except with finally块并告诉finally在任何情况下我都需要关闭文件,例如:

def read_file(data_file):
    # data_file = '\rr\ex.xlsx'
    sheets = {}
    try:
        print("Reading file: "+data_file)
        sheets_file = open(data_file,'rb')
        sheets['df_1'] = pd.read_excel(sheets_file, 'SheetSum')
    except Exception as excpt:
        print("Exception occurred", exc_info=True)
    finally:
        sheets_file.close()
    return sheets

read_file(file)
shutil.move( file, dirpath +'\processed_files')


否则,文件在后台仍然保持打开状态。


如果存在finally,则它指定清理处理程序。执行try
子句,包括任何exceptelse子句。如果在任何子句中发生了
异常并且未对其进行处理,则将临时保存
异常。执行finally子句。如果
有一个已保存的异常,它将在finally finally子句引发另一个异常,则将已保存的
异常设置为新异常的上下文。


..更多此处

评论


您应该将open(data_file,'rb')用作src:pd.read_excel(src,'SheetSum')。它将自动关闭文件

– fferrin
20年6月22日在19:12

另外,您应该将此作为单独的问题发布。这个空间只是给定问题的答案

– fferrin
20年6月22日在19:13