问题:为什么我们在Python中需要“ finally”子句?

我不知道为什么我们需要finallytry...except...finally报表。我认为,此代码块

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

使用finally以下命令与此相同:

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

我想念什么吗?

I am not sure why we need finally in try...except...finally statements. In my opinion, this code block

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

is the same with this one using finally:

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

Am I missing something?


回答 0

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

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语句。

It makes a difference if you return early:

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

Compare to this:

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

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

Other situations that can cause differences:

  • If an exception is thrown inside the except block.
  • If an exception is thrown in run_code1() but it’s not a TypeError.
  • Other control flow statements such as continue and break statements.

回答 1

您可以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读者可能会觉得有趣的事情。

You can use finally to make sure files or resources are closed or released regardless of whether an exception occurs, even if you don’t catch the exception. (Or if you don’t catch that specific exception.)

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

In this example you’d be better off using the with statement, but this kind of structure can be used for other kinds of resources.

A few years later, I wrote a blog post about an abuse of finally that readers may find amusing.


回答 2

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

They are not equivalent. Finally code is run no matter what else happens. It is useful for cleanup code that has to run.


回答 3

除了上面的其他答案外,该finally子句无论执行什么都将else执行,而该子句仅在未引发异常的情况下才执行。

例如,无exceptions地写入文件将输出以下内容:

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子句无论有无异常都会执行。希望这可以帮助。

To add to the other answers above, the finally clause executes no matter what whereas the else clause executes only if an exception was not raised.

For example, writing to a file with no exceptions will output the following:

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

OUTPUT:

Writing to file.
Write successful.
File closed.

If there is an exception, the code will output the following, (note that a deliberate error is caused by keeping the file read-only.

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

OUTPUT:

Could not write to file.
File closed.

We can see that the finally clause executes regardless of an exception. Hope this helps.


回答 4

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

The code blocks are not equivalent. The finally clause will also be run if run_code1() throws an exception other than TypeError, or if run_code2() throws an exception, while other_code() in the first version wouldn’t be run in these cases.


回答 5

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

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

In your first example, what happens if run_code1() raises an exception that is not TypeError? … other_code() will not be executed.

Compare that with the finally: version: other_code() is guaranteed to be executed regardless of any exception being raised.


回答 6

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

如果finally存在,则指定“清理”处理程序。该try 子句被执行,包括any 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子句对于释放外部资源(例如文件或网络连接)都是有用的。

As explained in the documentation, the finally clause is intended to define clean-up actions that must be executed under all circumstances.

If finally is present, it specifies a ‘cleanup’ handler. The try clause is executed, including any except and else clauses. If an exception occurs in any of the clauses and is not handled, the exception is temporarily saved. The finally clause is executed. If there is a saved exception it is re-raised at the end of the finally clause.

An example:

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

As you can see, the finally clause is executed in any event. The TypeError raised by dividing two strings is not handled by the except clause and therefore re-raised after the finally clause has been executed.

In real world applications, the finally clause is useful for releasing external resources (such as files or network connections), regardless of whether the use of the resource was successful.


回答 7

完美的例子如下:

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)

Perfect example is as below:

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)

回答 8

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

我第二个@Byers的例子。

finally is for defining “clean up actions”. The finally clause is executed in any event before leaving the try statement, whether an exception (even if you do not handle it) has occurred or not.

I second @Byers’s example.


回答 9

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

在下面的示例中,我们不确切知道store_some_debug_info可能会引发哪种异常。

我们可以运行:

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

但是,大多数的短毛猫都会抱怨捉摸不清一个exceptions。另外,由于我们选择仅pass针对错误,因此该except块并没有真正增加价值。

try:
  store_some_debug_info()
finally:
  do_something_really_important()     

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

Finally can also be used when you want to run “optional” code before running the code for your main work and that optional code may fail for various reasons.

In the following example, we don’t know precisely what kind of exceptions store_some_debug_info might throw.

We could run:

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

But, most linters will complain about catching too vague of an exception. Also, since we’re choosing to just pass for errors, the except block doesn’t really add value.

try:
  store_some_debug_info()
finally:
  do_something_really_important()     

The above code has the same effect as the 1st block of code but is more concise.


回答 10

几年来专业地使用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.

Using delphi professionally for some years taught me to safeguard my cleanup routines using finally. Delphi pretty much enforces the use of finally to clean up any resources created before the try block, lest you cause a memory leak. This is also how Java, Python and Ruby works.

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

and resource will be cleaned up regardless of what you do between try and finally. Also, it won’t be cleaned up if execution never reaches the try block. (i.e. create_resource itself throws an exception) It makes your code “exception safe”.

As to why you actually need a finally block, not all languages do. In C++ where you have automatically called destructors which enforce cleanup when an exception unrolls the stack. I think this is a step up in the direction of cleaner code compared to try…finally languages.

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

回答 11

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

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

A try block has just one mandatory clause: The try statement. The except, else and finally clauses are optional and based on user preference.

finally: Before Python leaves the try statement, it will run the code in the finally block under any conditions, even if it’s ending the program. E.g., if Python ran into an error while running code in the except or else block, the finally block will still be executed before stopping the program.


回答 12

运行以下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))

每次尝试以下输入:

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

**在学习Python的初期。

Run these Python3 codes to watch the need of 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))

CASE2:

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

Try the following inputs each time:

  1. random integers
  2. correct code which is 586(Try this and you will get your answer)
  3. random strings

** At a very early stage of learning Python.


回答 13

我试图在要阅读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 子句被执行,包括any exceptelse子句。如果在任何子句中发生异常并且未对其进行处理,则将临时保存异常。该finally子句被执行。如果存在已保存的异常,则会在finally 子句末重新引发。如果finally子句引发另一个异常,则将保存的异常设置为新异常的上下文。

..更多这里

I was trying to run a code where i wanted to read excel sheets. Issue was, if there is a file which has no sheet named say : SheetSum I am not able to move it to error location!! Code i wrote was:

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

Giving Error :

[WinError 32] The process cannot access the file because it is being used by another process

I had to add full try except with finally block and tell finally i need to close the file in any case like:

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

Otherwise, file still remains open is the background.

If finally is present, it specifies a cleanup handler. The try clause is executed, including any except and else clauses. If an exception occurs in any of the clauses and is not handled, the exception is temporarily saved. The finally clause is executed. If there is a saved exception it is re-raised at the end of the finally clause. If the finally clause raises another exception, the saved exception is set as the context of the new exception.

..More Here


声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。