Python装饰器,就是复合函数


《python核心编程》这本书一看就知道是搞技术的人写的,和我以前看qt的某些书籍一样。东一榔头西一棒子。不过还好,python的大部分我都知道了,看这本书不过是在查漏补缺,而且本身也有C/C++的基础。如果是刚入门的同学,如果看这本书能看懂,那真是天才了。

不过如果你同我一样,抱着查漏补缺的态度,那么这本书会有很多闪光点。其中一个就是这个python装饰器。


复合函数

学过数学的人,应该都知道复合函数或者算子吧:z=h。g。f (h,g是算子,f是g算子的定义域), 圈是复合符号.这样就形成了一个复合函数链。前面算子的值域是后面算子的定义域(算子的复合顺序是从右到左)。

如果我们把python中的普通函数看作f,那么装饰器就是后面的g,h 算子 ,返回的z是与f具有接受相同参数能力的新函数f_new,那么我门在使用的时候直接输入f(),实际上就是使用的f_new()。

无参数装饰器

  • 现在简单来看下f_new=g。f的形式,也就是不带参数的装饰器。显然g的定义域是python的普通函数f,返回值是f_new。f_new与f具有接受相同参数的能力。

下面看看代码说明:

def foo():
    print 'in foo()'

def wrap(func):
    print 'in wrap'
    return func

这个foo()函数是普通的python函数,它可以作为算子g的输入;下面的wrap定义域是func函数,返回的也是一个与输入func同类型的函数,显然它就是算子g


@wrap
def foo():
    print 'in foo()'

foo()

现在有 foo=f_new=wrap 。 foo ; 现在再调用foo(),实际上就是调用的f_new()也就是 (wrap。foo) ()


带参数装饰器

  • 现在来看代参数的装饰器,其数学表达式为:f_new=g(x)。f  ;同样,f是我们的普通的python函数。不同的是先用算子g,生成一个新的算子g(x),g(x)的定义域才是f,返回的函数为与f同类型的f_new。

下面是代码说明:

def wrap_out(arg):
    print 'in wrap_out,and arg is %s'%arg
    def wrap_inner(func):
        print 'in wrap_inner'
        return func
    return wrap_inner

@wrap_out('test1')
def foo()
    print 'in foo'

foo()
现在就有foo=f_new=wrap_out(arg)。foo

写成方程组:

wrap_inner=wrap_out(arg) 

foo=wrap_inner(foo)

有了上面的理解后,就应该非常清楚,包装函数内部应该是什么结构,应该返回什么。只要把函数的复合链写出来,就很容易搞清楚装饰器的结构。

比如上面的带参数的装饰器,我看过很多同学写的解释,反正就是很复杂。但是如果把foo=wrap_out(arg)。foo 写出来分析下。wrap_out带参数arg,而且它返回的值必须能接受foo函数,也就是wrap_inner=wrap_out(arg),wrap_inner必须能接受foo作为输入。再着,wrap_inner(foo)返回的值必须是一个和原foo接受统一的参数的函数,。那整个结构就很清楚了。


很多装饰器的复合

现在来看一个比较复杂的,双重的装饰器。

def wrap_out2(arg):
    print('in wrap_out 2 ,and arg is %s'%arg)
    def wrap_inner2(func):
        print('in wrap_inner 2')
        func('in wrap 2 call func')
        def fun_new2():
            print('in func_new  22')
        return fun_new2
    return wrap_inner2

def wrap_out(arg):
    print('in wrap_out,and arg is %s'%arg)
    def wrap_inner(func):
        print('in wrap_inner')
        func()
        def func_new(h):
            print(h)
        return func_new
    return wrap_inner

#foo_new=wrap_out2('world') o wrap_out('hello') o foo

@wrap_out2('world')
@wrap_out('hello')
def foo():
    print('in foo')

foo()

输出结果为:

in wrap_out 2 ,and arg is world
in wrap_out,and arg is hello
in wrap_inner
in foo
in wrap_inner 2
in wrap 2 call func
in func_new  22

数学式子为:

foo=wrap_out2('world')。wrap_out('hello')。foo

通过输出结果可以判断其化解顺序为:
foo=wrap_inner2。wrap_out('hello')。foo

foo=wrap_inner2。wrap_inner。foo

也就是说算子化简是从左到右,而普通计算是从右到左。要是这样都不能理解装饰器,那就只有去撞墙了。^_^

还可以看到wrap_out 和wrap_out2的输入与输出是不同的,在数学上输入与输出相同称为变换,如果不同那么只能称为映射了。映射不能随意的匹配,在这里只能写成wrap_out2。wrap_out的形式,而不能颠倒它们的复合顺序。当然一般的装饰器,都是经过一定处理后,返回原函数,也就是变换。

综上:func=h([arg])。g([arg])。func =T 。func  ;T就是一个算子,它的定义域和值域都是接受相同参数的 func 。老func 输入 T 返回同类型的 新func 。也就是说装饰器就是算子T,整个算子T是func空间的变换;over



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值