设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

隐藏的Bug和乐趣:动态捕获Python异常

2013-5-13 10:34| 发布者: joejoe0332| 查看: 1869| 评论: 0|原作者: skylline, ajeelee|来自: oschina

摘要:   在讨论动态捕获异常时让我大吃一惊的是,可以让我找到隐藏的Bug和乐趣...   有问题的代码   下面的代码来自一个产品中看起来是好的抽象代码-slightly(!) .这是调用一些统计数据的函数,然后进行处理 . 首 ...

令人讨厌的(上段中提到的)

1>>> try:
2...    TypeError = ZeroDivisionError  # now why would we do this...?!
3...    1 / 0
4... except TypeError:
5...    print("Caught!")
6... else:
7...    print("ok")
8...
9Caught!

不仅仅是异常参数通过名称查找, - 其它的表达式也是这样工作的:

1>>> try:
2...     1 / 0
3... except eval(''.join('Zero Division Error'.split())):
4...     print("Caught!")
5... else:
6...     print("ok")
7...
8Caught!

异常参数不仅仅只能在运行时确定,它甚至可以使用在生命周期内的异常的信息. 以下是一个比较费解的方式来捕捉抛出的异常 - 但也只能如此了:

01>>> import sys
02>>> def current_exc_type():
03...     return sys.exc_info()[0]
04...
05>>> try:
06...     blob
07... except current_exc_type():
08...     print ("Got you!")
09...
10Got you!

很明显这才是我们真正要寻找的当我们写异常处理程序时, 我们应该首先想到的就是这种

(字节)代码

  为了确认它是如何在异常处理工作中出现的,我在一个异常的例子中运行 dis.dis(). (注意 这里的分解是在Python2.7 下 - 不同的字节码是Python 3.3下产生的,但这基本上是类似的):

01>>> import dis
02>>> def x():
03...     try:
04...         pass
05...     except Blobbity:
06...         print("bad")
07...     else:
08...         print("good")
09...
10>>> dis.dis(x)  # doctest: +NORMALIZE_WHITESPACE
11  2           0 SETUP_EXCEPT             4 (to 7)
12<BLANKLINE>
13  3           3 POP_BLOCK
14              4 JUMP_FORWARD            22 (to 29)
15<BLANKLINE>
16  4     >>    7 DUP_TOP
17              8 LOAD_GLOBAL              0 (Blobbity)
18             11 COMPARE_OP              10 (exception match)
19             14 POP_JUMP_IF_FALSE       28
20             17 POP_TOP
21             18 POP_TOP
22             19 POP_TOP
23<BLANKLINE>
24  5          20 LOAD_CONST               1 ('bad')
25             23 PRINT_ITEM
26             24 PRINT_NEWLINE
27             25 JUMP_FORWARD             6 (to 34)
28        >>   28 END_FINALLY
29<BLANKLINE>
30  7     >>   29 LOAD_CONST               2 ('good')
31             32 PRINT_ITEM
32             33 PRINT_NEWLINE
33        >>   34 LOAD_CONST               0 (None)
34             37 RETURN_VALUE

  这显示出了我原来预期的问题(issue). 异常处理"看起来"完全是按照Python内部机制在运行. 这一步完全没有必要知道关于后续的异常“捕获”语句, 并且如果没有异常抛出它们将被完全忽略了.SETUP_EXCEPT并不关心发生了什么, 仅仅是如果发生了异常, 第一个处理程序应该被评估,然后第二个,以此类推.

  每个处理程序都有两部分组成: 获得一个异常的规则, 和刚刚抛出的异常进行对比. 一切都是延迟的, 一切看起来正如对你的逐行的代码的预期一样, 从解释器的角度来考虑. 没有任何聪明的事情发生了,只是突然使得它看起来非常聪明.

  总结

  虽然这种动态的异常参数让我大吃一惊, 但是这当中包含很多有趣的应用. 当然去实现它们当中的许多或许是个馊主意,呵呵

  有时并不能总是凭直觉来确认有多少Python特性的支持 - 例如 在类作用域内 表达式和声明都是被显式接受的, (而不是函数, 方法, 全局作用域),但是并不是所有的都是如此灵活的. 虽然(我认为)那将是十分美好的, 表达式被禁止应用于装饰器 - 以下是Python语法错误:

1@(lambda fn: fn)
2def x():
3   pass

这个是尝试动态异常参数通过给定类型传递给第一个异常的例子, 静静的忍受重复的异常:

01>>> class Pushover(object):
02...     exc_spec = set()
03...
04...     def attempt(self, action):
05...         try:
06...             return action()
07...         except tuple(self.exc_spec):
08...             pass
09...         except BaseException as e:
10...             self.exc_spec.add(e.__class__)
11...             raise
12...
13>>> pushover = Pushover()
14>>>
15>>> for _ in range(4):
16...     try:
17...         pushover.attempt(lambda: 1 / 0)
18...     except:
19...         print ("Boo")
20...     else:
21...         print ("Yay!")
22Boo
23Yay!
24Yay!
25Yay!


酷毙
1

雷人

鲜花

鸡蛋
1

漂亮

刚表态过的朋友 (2 人)

  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部