【问题标题】:Are variables created in the except: stage available in the finally: stage?在 excerpt: stage 中创建的变量是否在 final: stage 中可用?
【发布时间】:2015-03-11 20:57:49
【问题描述】:

我有一个 try/except*n/finally 代码块,我想知道执行以下操作的正确方法是:

try:
    some_function()
except exceptions.ExceptionA as e:
    self.logger.error("Error")
    subject = 'error A'
    message = 'Check error A'
except exceptions.ExceptionB as b:
    self.logger.error("Error")
    subject = 'error A'
    message = 'Check error A'
finally:
    self.publish(subject, message)
    sys.exit()

【问题讨论】:

    标签: python python-3.x exception-handling try-catch-finally


    【解决方案1】:

    不,因为finally总是被执行,而不仅仅是在引发和处理异常时。它会在没有异常时执行,或者引发了您没有处理的异常,或者您使用了return 或在try 之外的循环中使用了continuebreak 等。

    如果处理了异常,那么您在except 套件中绑定的名称将在finally 套件执行时保持设置,但您需要先将它们设置为标记值以免在没有引发此类异常的情况下避免出现 NameErrorUnboundLocal 异常:

    subject = message = None
    try:
        some_function()
    except exceptions.ExceptionA as e:
        self.logger.error("Error")
        subject = 'error A'
        message = 'Check error A'
    except exceptions.ExceptionB as b:
        self.logger.error("Error")
        subject = 'error A'
        message = 'Check error A'
    finally:
        # message and subject *can* be bound to None now
        self.publish(subject, message)
        sys.exit()
    

    如果您想在引发和处理异常的情况下执行代码,则必须为每个except 套件显式执行此操作。在这种情况下,您不能使用 finally,除非进行额外检查(例如,您可以使用 subject is not None)。

    【讨论】:

    • 啊,是的,由于某种原因,我忘记了 finally 被调用,即使没有调用异常!谢谢!
    【解决方案2】:

    是的,您可以在 finally 块中使用来自 except 的变量,因为 Python 中的变量具有函数作用域。

    In [1]: try:
       ...:     raise ValueError()
       ...: except:
       ...:     x = 1
       ...: finally:
       ...:     print(x)
       ...:     
    1
    

    但您必须确保变量在所有代码路径中都已初始化。

    try:
        pass
    except:
        x = 1
    finally:
        print(x) # NameError
    

    通常,您将首先初始化变量:

    x = None
    try:
        ...
    except:
        x = ...
    finally:
        ... safe to use x here ...
    

    【讨论】:

    • @MartijnPieters:我很欣赏这个想法,但您只是将一段无法运行的代码翻译成另一段无法运行的代码。我更喜欢椭圆而不是 cmets,因为 cmets 在 Python 中不起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多