Chapter11 函数和函数式编程

python支持内嵌函数,也就是一个函数内部可以再声明一个函数。因为函数本身来说,就是类。

函数的装饰者

这就是装饰者模式。装饰者,在数学的表达很优雅 g(f(x))就是这种表达式。

关于装饰者的详解。在Java的装饰者模式,我们清楚是对一个接口的装饰。这和函数的装饰本质上是一样的。那么,在Java的装饰者模式中,是如何进行处理的呢?

1 需要传递一个接口对象,作为装饰类的参数 2 调用接口的时候,会先执行装饰的接口调用,再次执行真正本身的调用。

那么,上面的步骤在函数的装饰者中是如何执行?

无参函数装饰

print '... dec'
def dec():
    def wraper(f):
        print 'dec is called'
        return f

    return wraper

@dec()
def f():
    print 'f is called'

f()

逐条进行分析。

1 需要传递一个接口对象,作为装饰类的参数。这里的解释是,dec()中没有参数,那么 f 会作为参数传递给dec()中的第一个内部函数,也就是 wraper的参数。

2 执行。执行的时候,先执行 dec()->wraper->f 注意,最后返回的是f函数,也就是说经过装饰之后,最后返回的是f

有参数的装饰者

在这里必须搞清楚一点,就是在装饰者模式中,因为不论是装饰者还是被装饰者都是继承自同一个接口,所以,二者的接口是一样的,也就是参数是一样的。而在python的函数装饰中,可能就会产生不一样的参数。

def decarg(a, b):
    print 'decarg is called', a, b

    def wraper(func):
        def test(a, b):
            print 'test is called', a, b
            return func()

        return test

    return wraper

@decarg('a', 'b')
def farg():
    print 'farg is called'
    return 3

print farg('a', 'b')

输出:
... decarg
decarg is called a b
test is called a b
farg is called
3

继续逐个分析:

1 参数传递。这里显然 func就是 frag 函数。 2 执行。注意这里的,decagr和farg的参数是不一样的。那么如何来处理这个问题呢?增加了一个新的内部函数test.所以这里的调用顺序是这样的: decarg->wraper -> test ->func

这里看起来还有一点疑惑的地方,是什么呢?是不是感觉和无参的对比多了一层test? 如果去掉test,直接返回func呢?会得到一个错误。所以关于有参数的装饰器来说,farg('a', 'b')的参数 ('a','b')究竟传给了谁? 是 wraper函数的返回值。所以对于装饰器来说的真的执行顺序是这样的:

decarg => Run => return wraper => frag作为参数传递给wraper => wraper run => return test => ('a','b')作为参数传递给test => test run => frag Run=> return frag的执行结果

如果和类对比,到很有意思。 decarg类似于最外层的类,waper是接口的实现,执行完wraper,执行func. 而test是一个适配器,为了解决参数不一致的适配器,最终执行func.

注意:@decarg('a', 'b') 这里的'a','b'表示传递给decarg函数的,不是形参。

生成器

生成器函数和函数长成一个样子,难道是靠内部有yield来标识这是一个生成器吗?

def simpleGen():
    yield  1
    yield '2-->punch'

myG = simpleGen()
print myG.next()
print myG.next()

for eachItem in simpleGen():
    print eachItem

输出:
1
2-->punch
1
2-->punch

生成器的最大的威力在于进行“协同程序”作战。 yield 将当前程序挂起,然后去执行其他的程序,执行完其他程序再继续执行当前程序。可以进行多线程和多进程的程序的协同工作。

通过对生成器传递参数也可以。

count = counter(5)
print count.next(), count.next()

count.send(9)

print count.next()
count.close()

输出:
5 6
10

results matching ""

    No results matching ""