python装饰器和闭包

装饰器是一个可以接收一个callback作为参数并且返回一个callback引用的函数
闭包是一个返回函数的函数,可以存储外部函数的变量。python3用nonlocal关键字修改外部变量,python2用字典可以修改。两者都可以提高代码复用性。

闭包

一个简单的闭包,line函数存储了外部函数a,b变量。闭包的功能可以和一个简单类相同,因为可以存储变量。

def line_conf(a, b):
    def line(x):
        return a*x + b
    return line
line1 = line_conf(1, 1)
line2 = line_conf(4, 5)
print(line1(5))
print(line2(5))

修改外部函数的变量 用nonlocal python3。

def counter(start=0):
    def incr():
        nonlocal start
        start += 1
        return start
    return incr
c1 = counter(5)
print(c1())
print(c1())

装饰器

装饰器一个隐含的特点,会自动执行装饰器函数,带参数的装饰器会执行到第二层装饰器函数。
下面展示了常用的函数装饰器的使用:

import functools
def decorated1(func):  # 在函数前加日志
    print("log start")
    return func
def decorated2(func):
    @functools.wraps(func)  # 得到传进来的参数进行判断处理
    def inner(*args, **kwargs):
        print("log start")
        return func(*args, **kwargs)
    return inner
def decorated3(foo, bar="bar"):  # 传参数给装饰器做具体处理
    def actual_inner(func):
        @functools.wraps(func)
        def inner(*args, **kwargs):
            print("log start", foo, bar)
            return func(*args, **kwargs)
        return inner
    return actual_inner
@decorated3("foo")
def add(a, b):
    """add func doc."""
    return a + b
print(add(2, 3))

带有参数的装饰器decorated3的执行过程是:

@decorated3("foo") # 括号操作执行这个变成
@actual_inner 这样的装饰器
def add(a, b):
    pass

注意,即使不调用add方法actual_inner也会执行,只是inner要add方法调用罢了,理解下面的程序,URL_FUNC_DICT的数据什么时候产生。

《python装饰器和闭包》 装饰器demo.png

装饰器一般内部函数写return,多个装饰器从里向外执行。装饰器有基于闭包的特点,保存外部变量。

def foo(fun):
    print("foo init")
    l = []
    s = "sss"
    def inner():
        l.append(23)
        # nonlocal s
        s = "yyyy"
        print("inner fun")
        print("l:{}, s:{}".format(l, s))
    return inner
@foo
def bar():
    print("bar fun")
bar()
bar()

装饰器也可以将一个函数装饰返回为一个类,你可能需要重写cal方法,下面是一个例子

class Task(object):
    def __call__(self, *args, **kwargs):
        return self.run(*args, **kwargs)
    def run(self, *args, **kwargs):
        raise NotImplementedError('NotImplementedError')
    def identify(self):
        return "I am a task"
def task(func):
    class SubTask(Task):
        def run(self, *args, **kwargs):
            return func()
    return SubTask()
@task
def foo():
    print("1 + 1 = ", 2)
    return 2
res = foo()
    原文作者:Baloneo
    原文地址: https://www.jianshu.com/p/406d712f16a6
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞