Size: 255
Comment:
|
Size: 6530
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
||'''status'''|| 草稿 || HuangYi || 10%;提纲完成|| | ##language:zh #format rst |
Line 3: | Line 4: |
[[TableOfContents]] | .. contents:: |
Line 5: | Line 6: |
= Python 函数 = | :status: 草稿 ;HuangYi; 10%; |
Line 7: | Line 8: |
== 神奇的星号 == | =================== Python函数 =================== |
Line 9: | Line 12: |
== lambda == | 在介绍 python 函数之前不得不提的一个概念就是 python 的 callable 。 |
Line 11: | Line 14: |
== 闭包 == | 函数定义 ========== |
Line 13: | Line 17: |
== 装饰器 == | 神奇的星号 ============ |
Line 15: | Line 20: |
== 小结 == | lambda ========== |
Line 17: | Line 23: |
== 练习.进阶导读 == | 函数式编程 ============ |
Line 19: | Line 26: |
= 反馈 = [[PageComment2]] |
闭包(closure) =================== 装饰器(decorator) =================== :: @log def test(a, b): pass 其中 ``log`` 就是个别人写好的装饰器,作用就是在调用 ``test`` 的前后分别输出个 ``enter test`` 和 ``exit test`` ,使用符号 ``@`` 来应用这个装饰器。 用最容易理解的方式来说,装饰器其实很简单,我们给您看上面这段代码的另一种写法,就很清楚了: :: def test(a, b): pass test = log(test) 是的,上面两段代码完全等价!实际上在 python2.4 加上 ``@`` 语法之前,大家一直都是用后面这种方法做的。 是不是很简单?但其实又不是那么简单。要从复杂的来讲,它和所谓 AOP 之类的神秘概念都扯得上关系。但 python 就是这样,你总是能够以最简单的方式完成 一些看似复杂的工作 ;-) 那么这个 ``log`` 应该如何来写呢? 其实有经验的读者从后面这段代码中应该已经能够看出端倪。 ``log`` 无非就是接受一个函数作为参数同时返回一个新函数的函数,说起来像绕口令, 不如看代码: :: def log(func): def wrapper(*args, **kw): print 'enter', func.__name__ func(*args, **kw) print 'exit', func.__name__ wrapper.__name__ = func.__name__ wrapper.__globals__ = func.__globals__ #TODO: 好像还有其他的信息需要偷梁换柱,有待查资料。 return wrapper ``log`` 里面定义另一个叫 ``wrapper`` 的嵌套函数,它把所有接受到的参数简单地全部传给 ``func`` ,并在调用前后输出一些信息。 最后对 ``wrapper`` 的一些属性进行偷梁换柱之后,就将它返回了, 于是这个 ``wrapper`` 就变成了一个被包装过的如假包换的 ``func`` 了! 现在我们的 ``log`` 只是简单地将信息输出到了标准输出, 要是可以随意指定 ``log`` 输出到的文件该多好啊, 也就是说,我们希望 ``log`` 变成这样: :: @log(open('default.log', 'w')) # 这里 open 函数是以写方式打开一个文件,并返回这个文件对象 def test(a, b): pass 那么这个 ``log`` 应该怎么实现呢?我们先来看一下上面这个代码的等价版本: :: def test(a, b): pass test = log(open('default.log'))(test) 貌似这里括号有点多,但仔细分析一下就看得出来, ``log`` 还是一个函数,它接受一个文件对象做参数, 并返回一个新函数,而这个新函数就是上面说过的装饰器(也就是绕口令:接受一个函数作为参数并返回另一个函数的函数)。 ok,我们还是看代码吧: :: def log(fileobj): def logger(func): def wrapper(*args, **kw): print >> fileobj, 'enter', func.__name__ func(*args, **kw) print >> fileobj, 'exit', func.__name__ wrapper.__name__ = func.__name__ return wrapper return logger 理清思路了吗? ``open('default.log')`` 返回一个文件对象,然后我们把它传给了 ``log`` , ``log`` 返回了这个 ``logger`` 函数,然后我们调用这个 ``logger`` 函数,把 ``test`` 函数传给了它, 它再返回一个 ``wrapper`` 函数,而这个 ``wrapper`` 函数正是一个包装过了的“新” ``test`` 函数。 其实我们还是感觉这个 ``log`` 的功能有点弱,它只能记录下 enter、exit 和函数名, 作为一个有用的 ``log`` ,怎么说也应该能够记录下函数调用所用的参数和函数的返回值的吧,没问题: :: def log(fileobj): def logger(func): def wrapper(*args, **kw): print >> fileobj, 'calling function', func.__name__,\ 'with position arguments', ', '.join(map(str, args)),\ 'and keyword arguments',\ ', '.join('%s=%s'%key_value for key_value in kw.items()) result = func(*args, **kw) print >> fileobj, 'function', func.__name__, 'returns', result wrapper.__name__ = func.__name__ return wrapper return logger 从上面这个例子中你应该温习到了不少熟悉的内容了吧 ;-) 里面用到了字符串模板、字符串的 ``join`` 方法、 ``map`` 函数,Generator expressions、字典,不错,真是个好例子! 现在让我们打开 python shell,试试这个 log 的强大威力吧! 先把上面的代码拷进 python shell(你应该可以从光盘中找到代码), 然后: :: >>> import sys >>> @log(sys.stdout) # sys.stdout 就是标准输出,也就是 print 默认输出的地方 ... def plus(a, b): ... return int(a) + int(b) ... >>> plus(1, b=2) call function plus with position arguments 1 and keyword arguments b=2 function plus returns 3 >>> >>> logfile = open('func.log', 'w') >>> @log(logfile) ... def plus(a, b): ... return int(a) + int(b) ... >>> plus(1, b=2) >>> logfile.flush() >>> print open('func.log').read() call function plus with position arguments 1 and keyword arguments b=2 function plus returns 3 TODO:decorator tools 生成器(generator) ===================== :: >>> def number_generator(): ... i = 0 ... while True: ... yield i ... i += 1 ... >>> for item in number_generator(): ... print item ... 0 1 2 # 省略后面输出的无穷个数字 是不是很神奇?哈哈。啥?停不下来了?按一下 Ctrl+C 吧。 实际上,python 的生成器也可以有两种讲法, 从简单的来讲,它就是用来方便地实现迭代器,像上面用的那样。 从复杂的来讲呢,python 的生成器其实正是神秘的 continuation ! 实际上大部分时候我们都只需要把 yield 当成是快速实现迭代器的工具来用就行了。 TODO 小结 ========== 练习 =========== .. macro:: [[PageComment2(nosmiley=1, notify=1)]] |
.. contents:: :status: 草稿 ;HuangYi; 10%; =================== Python函数 =================== 在介绍 python 函数之前不得不提的一个概念就是 python 的 callable 。 函数定义 ========== 神奇的星号 ============ lambda ========== 函数式编程 ============ 闭包(closure) =================== 装饰器(decorator) =================== :: @log def test(a, b): pass 其中 ``log`` 就是个别人写好的装饰器,作用就是在调用 ``test`` 的前后分别输出个 ``enter test`` 和 ``exit test`` ,使用符号 ``@`` 来应用这个装饰器。 用最容易理解的方式来说,装饰器其实很简单,我们给您看上面这段代码的另一种写法,就很清楚了: :: def test(a, b): pass test = log(test) 是的,上面两段代码完全等价!实际上在 python2.4 加上 ``@`` 语法之前,大家一直都是用后面这种方法做的。 是不是很简单?但其实又不是那么简单。要从复杂的来讲,它和所谓 AOP 之类的神秘概念都扯得上关系。但 python 就是这样,你总是能够以最简单的方式完成 一些看似复杂的工作 ;-) 那么这个 ``log`` 应该如何来写呢? 其实有经验的读者从后面这段代码中应该已经能够看出端倪。 ``log`` 无非就是接受一个函数作为参数同时返回一个新函数的函数,说起来像绕口令, 不如看代码: :: def log(func): def wrapper(*args, **kw): print 'enter', func.__name__ func(*args, **kw) print 'exit', func.__name__ wrapper.__name__ = func.__name__ wrapper.__globals__ = func.__globals__ #TODO: 好像还有其他的信息需要偷梁换柱,有待查资料。 return wrapper ``log`` 里面定义另一个叫 ``wrapper`` 的嵌套函数,它把所有接受到的参数简单地全部传给 ``func`` ,并在调用前后输出一些信息。 最后对 ``wrapper`` 的一些属性进行偷梁换柱之后,就将它返回了, 于是这个 ``wrapper`` 就变成了一个被包装过的如假包换的 ``func`` 了! 现在我们的 ``log`` 只是简单地将信息输出到了标准输出, 要是可以随意指定 ``log`` 输出到的文件该多好啊, 也就是说,我们希望 ``log`` 变成这样: :: @log(open('default.log', 'w')) # 这里 open 函数是以写方式打开一个文件,并返回这个文件对象 def test(a, b): pass 那么这个 ``log`` 应该怎么实现呢?我们先来看一下上面这个代码的等价版本: :: def test(a, b): pass test = log(open('default.log'))(test) 貌似这里括号有点多,但仔细分析一下就看得出来, ``log`` 还是一个函数,它接受一个文件对象做参数, 并返回一个新函数,而这个新函数就是上面说过的装饰器(也就是绕口令:接受一个函数作为参数并返回另一个函数的函数)。 ok,我们还是看代码吧: :: def log(fileobj): def logger(func): def wrapper(*args, **kw): print >> fileobj, 'enter', func.__name__ func(*args, **kw) print >> fileobj, 'exit', func.__name__ wrapper.__name__ = func.__name__ return wrapper return logger 理清思路了吗? ``open('default.log')`` 返回一个文件对象,然后我们把它传给了 ``log`` , ``log`` 返回了这个 ``logger`` 函数,然后我们调用这个 ``logger`` 函数,把 ``test`` 函数传给了它, 它再返回一个 ``wrapper`` 函数,而这个 ``wrapper`` 函数正是一个包装过了的“新” ``test`` 函数。 其实我们还是感觉这个 ``log`` 的功能有点弱,它只能记录下 enter、exit 和函数名, 作为一个有用的 ``log`` ,怎么说也应该能够记录下函数调用所用的参数和函数的返回值的吧,没问题: :: def log(fileobj): def logger(func): def wrapper(*args, **kw): print >> fileobj, 'calling function', func.__name__,\ 'with position arguments', ', '.join(map(str, args)),\ 'and keyword arguments',\ ', '.join('%s=%s'%key_value for key_value in kw.items()) result = func(*args, **kw) print >> fileobj, 'function', func.__name__, 'returns', result wrapper.__name__ = func.__name__ return wrapper return logger 从上面这个例子中你应该温习到了不少熟悉的内容了吧 ;-) 里面用到了字符串模板、字符串的 ``join`` 方法、 ``map`` 函数,Generator expressions、字典,不错,真是个好例子! 现在让我们打开 python shell,试试这个 log 的强大威力吧! 先把上面的代码拷进 python shell(你应该可以从光盘中找到代码), 然后: :: >>> import sys >>> @log(sys.stdout) # sys.stdout 就是标准输出,也就是 print 默认输出的地方 ... def plus(a, b): ... return int(a) + int(b) ... >>> plus(1, b=2) call function plus with position arguments 1 and keyword arguments b=2 function plus returns 3 >>> >>> logfile = open('func.log', 'w') >>> @log(logfile) ... def plus(a, b): ... return int(a) + int(b) ... >>> plus(1, b=2) >>> logfile.flush() >>> print open('func.log').read() call function plus with position arguments 1 and keyword arguments b=2 function plus returns 3 TODO:decorator tools 生成器(generator) ===================== :: >>> def number_generator(): ... i = 0 ... while True: ... yield i ... i += 1 ... >>> for item in number_generator(): ... print item ... 0 1 2 # 省略后面输出的无穷个数字 是不是很神奇?哈哈。啥?停不下来了?按一下 Ctrl+C 吧。 实际上,python 的生成器也可以有两种讲法, 从简单的来讲,它就是用来方便地实现迭代器,像上面用的那样。 从复杂的来讲呢,python 的生成器其实正是神秘的 continuation ! 实际上大部分时候我们都只需要把 yield 当成是快速实现迭代器的工具来用就行了。 TODO 小结 ========== 练习 =========== .. macro:: [[PageComment2(nosmiley=1, notify=1)]]