第十一章 函数和函数式编程
1.函数定义举例:
[a]只包含形参列表
def func(arg1,arg2) :
[b]包含形参列表和默认参数
def func(arg1,arg2,arg3='default'):
[c]包含形参列表,默认参数和非关键字变长参数
def func(arg1,arg2,arg3='default',*nonkey_varlist)
[d]包含形参列表,默认参数,非关键字变长参数和关键字变长参数
def func(arg1,arg2,arg3='default',*nonkey_varlist,**key_varlist)
2.函数的调用
以上节[d]为例,有下面三种调用方法
[1] func(1,2,'hehe','a','b','c,','key1'='one','key2'='two')
[2] func(1,2,'hehe',*('a','b','c'),**{'key1'='one','key2'='two'})
[3] nonkey_vl=('a','b','c')
key_vl={'key1'='one','key2'='two'}
func(1,2,'hehe',*nonkey_vl,**key_vl)
3.函数装饰器
(1)作用:与java AOP类似,提供事务、性能统计、日志等切面功能
(2)用法:
[a]无参数的函数装饰器
无参装饰器是一个以函数对象作为参数,返回值为函数对象的函数。
def dc(func):
def wrappedFunc(*args,**kargs):
...//do sth
return func(*args,**kargs)
return wrappedFunc
@dc
def foo(*args,**kargs):
...//do sth
foo(...) //invoke
效果:foo(...) = dc(foo)(...)
[b]有参数的函数装饰器
有参数的函数装饰器,是一个有参数并且返回值为函数对象的函数,返回的函数对象仍然是个函数装饰器(通常是个无参函数数装饰器)
def dc(dc_args):
def wrappedFunc0(f):
def innerWrapped0(*args,**kargs):
...//do sth
return f
return wrappedFunc0
def wrappedFunc1(f):
def innerWrapped1(*args,**kargs):
...//do sth
return f
return wrappedFunc1
... //process dc_args
return wrappedFuncX
@dc('a')
def foo(...):
...//do sth
foo(...) //invoke
效果 : foo(...) = dc('a')(f)(...)
(3)misc:
函数装饰器效果可以叠加,如
@dc1
@dc2
def foo():
...
foo() 效果等同于 dc1(dc2(f))
4.函数式编程
(1)lambda表达式:返回一个可调用的函数对象
用法:
a = lambda x,y=2 : x + y
a(3) //invoke
a(3,3) //invoke
它等价于
def a(x,y=2):
return x+y
(2)内建函数:apply(已废弃,由可变长参数列表代替),filter,map,reduce
filter : 过滤列表里的非真元素并生成新列表
map : 将列表的每个元素做为参数传给某个函数,并按顺序生成返回值序列
reduce :将列表第一个和第二个元素传给函数,生成返回值,再将此值与第三个元素传给函数,依次执行最终得到一个返回值。典型例子是计算阶乘。
5.python的闭包
闭包是指有权限访问另一个函数作用域的变量的函数,创建闭包的常见方式就是在一个函数内部创建另一个函数。
例子:
def counter(arg=10):
count = [arg]
def incr():
count[0] += 10
return count
return incr
ret = counter(15)
print ret()
输出 :25
def counter(arg=10):
count = arg
def incr():
count += 20
return count
print count
return incr
ret = counter(15)
print ret()
输出错误 : local variable 'count' referenced before assignment
def counter(arg=10):
count = arg
def incr():
count = 100
return count
print count
return incr
ret = counter(15)
print ret()
输出:
15
100
【例】一个结合闭包和函数装饰器的例子
from time import time
'''
该例子演示了函数装饰器和闭包
首先,logged('pre')返回一个无参函数装饰器pre_logged,然后hello0再经过pre_logged装饰
hell0("world") 等价于 logged('pre')(hello0)('world')
'''
def logged(when):
def log(f,*args,**kargs):
print '''Called:
function : %s
args : %r
kargs : %r''' % (f,args,kargs)
def pre_logged(f):
def wrapper(*args,**kargs):
log(f,*args,**kargs)
return f(*args,**kargs)
return wrapper
def post_logged(f):
def wrapper(*args,**kargs):
now = time()
try:
return f(*args,**kargs)
finally:
log(f,*args,**kargs)
print 'time delta: %s' % (time()-now)
return wrapper
try:
return {"pre":pre_logged,"post":post_logged}[when]
except KeyError,e:
raise ValueError(e),'must be "pre" or "post"'
@logged("pre")
def hello0(name):
print "hello," , name
@logged("post")
def hello1(name):
print "hello," , name
hello0("world")
print ''
hello1("world")
6.python的生成器
生成器是一个带yield语句的函数,一个函数或子程序只返回一次,但生成器能暂停执行并返回一个中间的结果——那就是yield的功能,返回一个值给调用者并暂停执行。当生成器的next方法被调用的时候,它会准确地从离开地方继续,直到遇到yield语句停止。带yield语句的函数的真正返回值是生成器。所以不能在这种函数里用return。
yield后面的参数就是生成器next方法的返回值(中间结果),而yield表达式自己有个返回值。
send的参数是yield表达式的返回值,而send的返回值是下一次yield的返回的中间结果。
【例】
from time import sleep
def counter(start_at=0):
print 'first invoke'
count = start_at
while True:
val = (yield count)
sleep(2)
print ' count %s' % count
if val is not None:
sleep(2)
print ' set count to %s' % val
count = val
else:
count += 1
g = counter(3)
print 'next : %s' % g.next()
print 'next : %s' % g.next()
print 'next : %s' % g.next()
print 'begin to send'
print 'send : %s' % g.send(100) //此处输出100,而不是5,因为send的执行过程会跳过一次yield
print 'next : %s' % g.next()
g.close()
# print g.next()
结果:
first invoke
next : 3
count 3
next : 4
count 4
next : 5
begin to send
count 5
set count to 100
send : 100
count 100
next : 101
第十二章:模块
1.模块导入
import module1
import module2,module3
from module4 import funcA
from module4 import varB
from module4 import classC
import longNameModule5 as m5
from module6 import longNamefuncB as funcB
模块可以导入多次,但只会加载一次。加载时,模块顶层代码会被执行,因此在模块顶层中最好只定义函数,类和全局变量。
局部命名空间会覆盖导入的命名空间,如下
from time import sleep
def sleep(sec):
print 'mock sleep , do nothing'
sleep(3)
print "finish"
结果:
mock sleep, do nothing
finish
如果删去def sleep...代码段,则真正sleep会被调用。
如果不想某个模块属性被导入,可以让该属性吗以下划线开头。但是,如果显式地导入该模块属性,则加下划线也不起作用。
关于__future__(待续)
警告框架(待续)
2.包
相对导入:在不指明 package 名的情况下导入自己这个 package 的模块,比如一个 package 下有 a.py 和 b.py 两个文件,在 a.py 里 from . import b 即是相对导入 b.py。
绝对导入:指明顶层 package 名。比如 import a,Python 会在 sys.path 里寻找所有名为 a 的顶层模块。
from __future__ import absolute_import: 在 3.0 以前的旧版本中启用相对导入等特性所必须的 future 语句。