zoukankan      html  css  js  c++  java
  • Python闭包及装饰器

    Python闭包

     先看一个例子:

    def outer(x):
        def inner(y):
            return x+y
        return innder
    
    add = outer(8)
    print add(6)

    我们定义了一个方法outer,方法内部又定义了一个方法inner,方法outer返回值为内部定义的方法inner。

    同时,内部方法innder使用了外部方法的参数x。

    从我们的调用方式可以清晰地看到,add=outer(8)相当于add接受了类似于下边一个方法

    def inner(y):
        return 8+y

    然后调用add(6),结果显示14

    这其实就是一个简单的闭包。

    python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。

    下边是另一个闭包的实例--方法作为参数传递

    def tsfunc(func,x):
        def wrappedFunc():
            print func.__name__
            return func(x)
        return wrappedFunc()
    
    def foo(x):
        print 'aaa' + x
    
    if __name__=='__main__':
        tsfunc(foo , "x")

    结果是:

    foo
    aaax

    我们把方法foo当做参数传递到另一个方法tsfunc内,然后在tsfunc内做了其他一些事情(这里我们只是打印了foo的name),最后又返回来foo,并使用了额外参数。

    装饰器

    不带参数的装饰器

    和上边一样,举个例子,如下:

    def decorator(F):
        def new_F(a, b):
            print "input", a, b
            return F(a, b)
        return new_F
    
    @decorator
    def sub(a,b):
        return a-b
    
    def add(a,b):
        return a+b
    
    
    print sub(3,4)
    
    add = decorator(add)
    print add(3, 4)

    结果如下:

    input 3 4
    -1
    input 3 4
    7

    对比sub的调用和add的调用,其实他们是完全一样的运行方式,只不过装饰器将语法包裹起来,看起来更干净一些。

    或许你现在发现一个问题,如果我们要给装饰器加参数,在被装饰的方法内部使用该怎么做呢?

    装饰器工厂(带参数的装饰器)

    在装饰器基础上再增加一层嵌套,其定义和实现装饰器是一样的,看下边的例子:

    # a new wrapper layer
    def pre_str(pre=''):
        # old decorator
        def decorator(F):
            def new_F(a, b):
                print(pre + "input", a, b)
                return F(a, b)
            return new_F
        return decorator
    
    @pre_str('^_^')
    def sub(a,b):
        return a-b
    
    def add(a,b):
        return a+b
    
    
    print sub(3,4)
    
    dec = pre_str('&_&')
    add = dec(add)
    print add(3, 4)

    这个也是很好理解的了吧,我们的装饰运行方式和分步调用是同一个效果的。

    这样就实现了装饰器语法传递参数,效果还不错。

    类装饰器

    看下边例子:

    def decorator(aClass):
        class newClass:
            def __init__(self, age):
                self.total_display   = 0
                self.wrapped         = aClass(age)
            def display(self):
                self.total_display += 1
                print "total display:%s" % self.total_display
                self.wrapped.display()
        return newClass
    
    @decorator
    class Bird:
        def __init__(self, age):
            self.age = age
        def display(self):
            print "My age is %s"% self.age
    
    eagleLord = Bird(5)
    for i in range(3):
        eagleLord.display()

    运行结果:

    定义了decorator作用给类Bird,当初始化Bird类时,装饰器会先进行初始化,使用Bird初始化的参数,然后返回一个装饰器内定义的类。

    例子中装饰器内的类包裹了一个Bird类实例,并实例化。根据单步调试来看,Bird类初始化只进行了一次,即相当于Bird的初始化时在装饰器内被调用生成实例时调用的。

    要注意的是:Bird(5)的返回值并不是Bird实例,而是装饰器内的类newClass实例

    那么剩下的就是很简单的方法调用了。

  • 相关阅读:
    2. redis的数据类型
    1. redis简介
    6. 职责链设计模式
    9. 桥梁设计模式
    一. 序言
    网络中常见的面试题
    JDBC
    Mybatis批量操作数据的方法
    ORM框架的概述
    Mybatis动态sql技术
  • 原文地址:https://www.cnblogs.com/cotton/p/3939990.html
Copyright © 2011-2022 走看看