笨办法学Python记录--习题37 异常,lambda,yield,转义序列

习题中提到了raise,查了下,顺便所有异常类关键字罗列如下文章中:                                  

为什么使用异常

错误处理、事件通知、特殊情况处理、退出时的行为、不正常的程序流程。

简单的示例

在没有任何定义x变量的时候:

print x
print 1

将会抛出NameError异常:

NameError: name 'x' is not defined

而且1并不会被输出,也就是说程序将被中断。如果讲代码修改如下:

try:
print x
exceptNameError:
print "Something is wrong!"
print 1

得到的输出将是:

Something is wrong!
1

可见,我们定义的except会“抓住”NameError类型的语句,并且执行相应的处理代码,而且程序不会被中断。

使用raise

我们可以自己触发异常,例如:

raise IndexError

Python会返回:

Traceback (most recent call last):
File "d:\我的文档\桌面\todo\exep.py", line 1, in <module>
raise IndexError
IndexError

自定义的异常

下面定义了一个MyException类,它继承自Python内置的Exception类。

class MyException(Exception):pass
try:
#some code here
raise MyException
except MyException:
print "MyException encoutered"

结果为:

MyException encoutered

可以在一个except内捕获多个异常:

except (AttributeError, TypeError, SyntaxError):
  

捕获所有异常

只要在except后面不加任何异常类型,这个except块就可以捕获所有的异常。

except:

捕获异常的继承关系

当我们except Super的时候,同样会捕获到raise Sub的异常。

finally

无论try块是否抛出异常,永远执行的代码。通常用来执行关闭文件,断开服务器连接的功能等等。

class MyException(Exception):pass
try:
#some code here
raise MyException
except MyException:
print "MyException encoutered"
finally:
print "Arrive finally"

结果:

MyException encoutered
Arrive finally

try、except、else

可以在try块里加入else块,代码块将在没有异常被抛出的时候执行:

try:
print "normal code here"
except MyException:
print "MyException encoutered"
else:
print "No exception"

finally:
print "Arrive finally"

结果为:

normal code here
No exception
Arrive finally

raise异常、同时添加数据

raise异常的同时,我们可以添加一些额外的数据,就像下面的例子一样:

class MyException(Exception):pass
try:
raise MyException,", and some additional data"
except MyException,data:
print "MyException encoutered"
print data

断言assert

断言是指期望指定的条件满足,如果不满足则抛出AssertionError异常。例如:

def positive(x):
assert x > 0
print "x"
positive(1)
positive(0)

positive(0)一句将会抛出一个异常。

with/as

with/as语句主要是为了代替try/finally语句、通常用来做一些善后工作或者是清理现场的工作。

with open('test.txt') as myfile:
for line in myfile:
#code here
#code here

当with代码块结束之后,文件将会自动关闭。这是因为返回的对象支持context management protocol。原书598页有关于该协议的讨论,例如如何自定义一个支持该协议、从而支持with语句的类。

yield:貌似是个迭代常量的标记,详细参考“文章”里的一篇。

lambda函数介绍

在学习python的过程中,lambda的语法时常会使人感到困惑,lambda是什么,为什么要使用lambda,是不是必须使用lambda?

  下面就上面的问题进行一下解答。

  1、lambda是什么?

    看个例子:     

1 g = lambda x:x+1

  看一下执行的结果: 

  g(1)

  >>>2

  g(2)

  >>>3

  当然,你也可以这样使用:

  lambda x:x+1(1)

  >>>2   

  可以这样认为,lambda作为一个表达式,定义了一个匿名函数,上例的代码x为入口参数,x+1为函数体,用函数来表示为:

1 def g(x):
2 return x+1

  非常容易理解,在这里lambda简化了函数定义的书写形式。是代码更为简洁,但是使用函数的定义方式更为直观,易理解。

  Python中,也有几个定义好的全局函数方便使用的,filter, map, reduce  

复制代码
>>> foo = [2, 18, 9, 22, 17, 24, 8, 12, 27]
>>>
>>> print filter(lambda x: x % 3 == 0, foo)
[18, 9, 24, 12, 27]
>>>
>>> print map(lambda x: x * 2 + 10, foo)
[14, 46, 28, 54, 44, 58, 26, 34, 64]
>>>
>>> print reduce(lambda x, y: x + y, foo)
139
复制代码

  上面例子中的map的作用,非常简单清晰。但是,Python是否非要使用lambda才能做到这样的简洁程度呢?在对象遍历处理方面,其实Python的for..in..if语法已经很强大,并且在易读上胜过了lambda。

  比如上面map的例子,可以写成:

    print [x * 2 + 10 for x in foo]

  非常的简洁,易懂。

  filter的例子可以写成:

    print [x for x in foo if x % 3 == 0]

  同样也是比lambda的方式更容易理解。


  上面简要介绍了什么是lambda,下面介绍为什么使用lambda,看一个例子(来自apihelper.py):  

processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)

  在Visual Basic,你很有可能要创建一个函数,接受一个字符串参数和一个 collapse 参数,并使用 if 语句确定是否压缩空白,然后再返回相应的值。这种方式是低效的,因为函数可能需要处理每一种可能的情况。每次你调用它,它将不得不在给出你所想要的东西之前,判断是否要压缩空白。在 Python 中,你可以将决策逻辑拿到函数外面,而定义一个裁减过的 lambda 函数提供确切的 (唯一的) 你想要的。这种方式更为高效、更为优雅,而且很少引起那些令人讨厌 (哦,想到那些参数就头昏) 的错误。

  通过此例子,我们发现,lambda的使用大量简化了代码,使代码简练清晰。但是值得注意的是,这会在一定程度上降低代码的可读性。如果不是非常熟悉python的人或许会对此感到不可理解。


  lambda 定义了一个匿名函数

  lambda 并不会带来程序运行效率的提高,只会使代码更简洁。

  如果可以使用for...in...if来完成的,坚决不用lambda。

  如果使用lambda,lambda内不要包含循环,如果有,我宁愿定义函数来完成,使代码获得可重用性和更好的可读性。


  总结:lambda 是为了减少单行函数的定义而存在的。

 字符串转义序列:




\f 匹配一个换页符。等价于\x0c和\cL。
\v 匹配一个垂直制表符。等价于\x0b和\cK。

 

转义字符描述
\(在行尾时) 续行符
\\ 反斜杠符号
\’ 单引号
\” 双引号
\a 响铃
\b 退格(Backspace)
\e 转义
\000
\n 换行
\v 纵向制表符
\t 横向制表符
\r 回车
\f 换页
\oyy 八进制数yy代表的字符,例如:\o12代表换行
\xyy 十进制数yy代表的字符,例如:\x0a代表换行
\other 其它的字符以普通格式输出

     

Python格式化字符串的替代符以及含义

    符   号     说     明
      %c  格式化字符及其ASCII码
      %s  格式化字符串
      %d  格式化整数
      %u  格式化无符号整型
      %o  格式化无符号八进制数
      %x  格式化无符号十六进制数
      %X  格式化无符号十六进制数(大写)
      %f  格式化浮点数字,可指定小数点后的精度
      %e  用科学计数法格式化浮点数
      %E  作用同%e,用科学计数法格式化浮点数
      %g  根据值的大小决定使用%f活%e
      %G  作用同%g,根据值的大小决定使用%f活%e
      %p  用十六进制数格式化变量的地址

 

 

Python语言中的@符号有比较特殊的含义,而且是一种比较稀有的特性,初学者往往不容易理解,这里就其做一些解释。 首先看一段代码:

?Download download.txt
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def minus(f):
    print 'minus'
    f()
 
def plus(f):
    print 'plus'
    f()
 
def test(a):
    if a > 3 : return plus
    else : return minus
 
@test(5)
def xxx():
    print 'ok'

解释器首先会解释@符号后面的代码,如果如上面的代码类似,那么test(5)将被执行,因为test参数5大于3,所以会返回一个函数指针plus(可以用C的这个名字来理解),plus将下一行的函数指针xxx当作参数传入,直到执行完成。最后结果将输出‘plus’和‘ok’。 有时候可能是下面这种形式:

?Download download.txt
 
1
2
3
4
5
6
7
def minus(f):
    print 'minus'
    f()
 
@minus
def xxx():
    print 'ok'

minus因为本身已经是一个函数指针,所以会直接以xxx作为参数传入,结果会输出‘minus’和‘ok’。

posted on 2014-04-18 22:32  麦兜布熊  阅读(537)  评论(0编辑  收藏  举报