令人讨厌的(上段中提到的)
2 | ... TypeError = ZeroDivisionError |
不仅仅是异常参数通过名称查找, - 其它的表达式也是这样工作的:
3 | ... except eval (' '.join(' Zero Division Error'.split())): |
异常参数不仅仅只能在运行时确定,它甚至可以使用在生命周期内的异常的信息. 以下是一个比较费解的方式来捕捉抛出的异常 - 但也只能如此了:
02 | >>> def current_exc_type(): |
03 | ... return sys.exc_info()[ 0 ] |
07 | ... except current_exc_type(): |
很明显这才是我们真正要寻找的当我们写异常处理程序时, 我们应该首先想到的就是这种 (字节)代码
为了确认它是如何在异常处理工作中出现的,我在一个异常的例子中运行 dis.dis(). (注意 这里的分解是在Python2.7 下 - 不同的字节码是Python 3.3下产生的,但这基本上是类似的):
11 | 2 0 SETUP_EXCEPT 4 (to 7 ) |
14 | 4 JUMP_FORWARD 22 (to 29 ) |
17 | 8 LOAD_GLOBAL 0 (Blobbity) |
18 | 11 COMPARE_OP 10 (exception match) |
19 | 14 POP_JUMP_IF_FALSE 28 |
24 | 5 20 LOAD_CONST 1 ( 'bad' ) |
27 | 25 JUMP_FORWARD 6 (to 34 ) |
30 | 7 >> 29 LOAD_CONST 2 ( 'good' ) |
33 | >> 34 LOAD_CONST 0 ( None ) |
这显示出了我原来预期的问题(issue). 异常处理"看起来"完全是按照Python内部机制在运行.
这一步完全没有必要知道关于后续的异常“捕获”语句, 并且如果没有异常抛出它们将被完全忽略了.SETUP_EXCEPT并不关心发生了什么,
仅仅是如果发生了异常, 第一个处理程序应该被评估,然后第二个,以此类推.
每个处理程序都有两部分组成: 获得一个异常的规则, 和刚刚抛出的异常进行对比. 一切都是延迟的, 一切看起来正如对你的逐行的代码的预期一样, 从解释器的角度来考虑. 没有任何聪明的事情发生了,只是突然使得它看起来非常聪明. 总结
虽然这种动态的异常参数让我大吃一惊, 但是这当中包含很多有趣的应用. 当然去实现它们当中的许多或许是个馊主意,呵呵
有时并不能总是凭直觉来确认有多少Python特性的支持 - 例如 在类作用域内 表达式和声明都是被显式接受的, (而不是函数, 方法,
全局作用域),但是并不是所有的都是如此灵活的. 虽然(我认为)那将是十分美好的, 表达式被禁止应用于装饰器 - 以下是Python语法错误:
这个是尝试动态异常参数通过给定类型传递给第一个异常的例子, 静静的忍受重复的异常:
01 | >>> class Pushover( object ): |
04 | ... def attempt( self , action): |
07 | ... except tuple ( self .exc_spec): |
09 | ... except BaseException as e: |
10 | ... self .exc_spec.add(e.__class__) |
13 | >>> pushover = Pushover() |
17 | ... pushover.attempt( lambda : 1 / 0 ) |
|