为什么我们需要“最终”;子句?

我不确定为什么在try...except...finally语句中需要finally。在我看来,这个代码块

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

与使用finally的这个相同:

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

我遗漏了什么吗?

191820 次浏览

如果你早点回来,情况就不一样了:

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语句。
它们是不相等的。不管发生什么,finally代码都会运行*。 它对于清理必须运行的代码非常有用
< p > : 正如马克·拜尔斯注释的那样,任何导致进程立即终止的事情也会阻止finally-code运行。 后者可以是os._exit().或powercut,但无限循环或其他东西也属于这一类

代码块是不等效的。如果run_code1()抛出TypeError以外的异常,或者run_code2()抛出异常,finally子句也将运行,而第一个版本中的other_code()在这些情况下不会运行。

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

将其与finally:版本进行比较:无论引发任何异常,other_code()都保证被执行。

你可以使用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的文章,读者可能会觉得很有趣。

finally用于定义“清理行动”finally子句在离开try语句之前的任何事件中都会被执行,无论是否发生异常(即使你没有处理它)。

我赞同拜尔斯的例子。

Finally也可以用于在运行主要工作的代码之前运行“可选”代码,而可选代码可能由于各种原因而失败。

在下面的例子中,我们并不确切地知道store_some_debug_info可能抛出什么样的异常。

我们可以运行:

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

但是,大多数lint会抱怨捕捉到的异常过于模糊。此外,由于我们选择仅pass来处理错误,因此except块并没有真正增加值。

try:
store_some_debug_info()
finally:
do_something_really_important()

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

完美的例子如下:

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)

正如文档中所解释的,finally子句旨在定义必须执行在任何情况下的清理操作。

如果finally存在,它指定一个' cleanup '处理程序。的try 子句被执行,包括任何exceptelse子句。如果一个 异常发生在任何子句中而不被处理,则 异常被暂时保存。finally子句被执行。如果 有一个保存的异常,它在finally的末尾被重新引发 条款。< / p >

一个例子:

>>> 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子句用于释放外部资源(例如文件或网络连接),而不管资源的使用是否成功。

为了补充上面的其他答案,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子句都会执行。希望这能有所帮助。

专业地使用delphi几年教会了我如何使用最后来保护我的清理程序。Delphi在很大程度上强制使用finally来清理try块之前创建的任何资源,以免导致内存泄漏。这也是Java、Python和Ruby的工作原理。

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

不管你在try和finally之间做了什么,资源都会被清理。而且,如果执行从未到达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.
try块只有一个强制子句:try语句。 except, else和finally子句是可选的,基于用户的首选项 < p >最后: 在Python离开try语句之前,它将在任何条件下运行finally块中的代码,即使它正在结束程序。例如,如果Python在except或else块中运行代码时遇到错误,finally块仍将在停止程序之前执行

运行这些Python3代码来查看finally的需求:

CASE1:

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))

每次尝试以下输入:

  1. 随机整数
  2. 正确的代码是586(试试这个,你会得到你的答案)
  3. 随机字符串

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

我试图运行一个代码,我想读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 = {}
sheets_file = None
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:
if sheets_file:
sheets_file.close()
return sheets


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

否则,文件仍然保持打开是后台。

如果finally存在,它指定一个清理处理程序。的try 子句被执行,包括任何exceptelse子句。如果一个 异常发生在任何子句中而不被处理,则 异常被临时保存finally子句被执行。如果 有一个保存的异常,它在finally的末尾被重新引发 条款。如果finally子句引发另一个异常,则保存

. Exception被设置为新异常的上下文

..更多在这里

试着先运行这段代码,不要使用finally块,

1 / 0导致除零错误。

    try:
1 / 0
print(1)
        

except Exception as e:
1 / 0
print(e)
        

然后尝试运行这段代码,

    try:
1 / 0
print(1)
        

except Exception as e:
1 / 0
print(e)
   

finally:
print('finally')
对于第一种情况,你没有finally块,
因此,当在except块中发生错误时,程序执行将停止,并且在except块之后不能执行任何东西 但是对于第二种情况,
错误发生,但在程序停止之前,python先执行finally块,然后导致程序停止。
这就是为什么你用finally来做真正重要的事情。

下面是一段代码来澄清两者的区别:

...


try:
a/b
print('In try block')
  

except TypeError:
print('In except block')
  

finally:
print('In finally block')


print('Outside')

a, b = 0, 1

输出:

In try block
In finally block
Outside

(没有错误,除了跳过块。)


a, b = 1, 0

输出:

In finally block


Traceback (most recent call last):
a/b
ZeroDivisionError: division by zero

(没有为ZeroDivisionError和只有finally块被执行。指定异常处理)


a, b = 0, '1'

输出:

In except block
In finally block
Outside

(异常被正确处理,程序没有中断。)


注意:如果你有一个除了块来处理所有类型的错误,最后块将是多余的。

只是为了让这个答案上的Abhijit Sahu的注释更好看,并突出显示语法:

像这样,你可以观察到在以下情况下哪个代码块发生了什么:

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)

在这里你可以看到try, except, else, and finally是如何一起工作的。实际上,由于你的代码没有“其他”,那么你所声称的是正确的。也就是说,你写的两个语句之间有没有差异。但如果“其他”在某个地方被使用,那么“最后'就会有所不同