python-闭包、装饰器

136 阅读3分钟

什么是闭包

在一个内部函数中,对外部作用域的变量进行引用,(并且一般外部函数的返回值为内部函数),那么内部函数就被认为是闭包。简而言之,闭包指延伸作用域的函数。 闭包有两个要素:

  • 嵌套在另一个函数中的函数
  • 自由变量的引用

什么是装饰器?

所谓的装饰器,其实就是通过装饰器函数,来修改原函数的一些功能,使得原函数不需要修改

  • 装饰器本质上是一个Python函数, 它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,提高了代码的复用性。
  • 装饰器是一个函数,它接收一个函数返回另一个函数。
  • 使用内置的装饰器@functools.wrap,它会帮助保留原函数的元信息(也就是将原函数的元信息,拷贝到对应的装饰器函数里)

装饰器主要有以下功能:

  • 引入日志。
  • 函数执行时间统计,记录函数的耗时 计算latency
  • 执行函数前预备处理。
  • 执行函数后的清理功能。
  • 权限校验等场景。
  • 缓存
  • 用户审计,记录用户行为 请求的uri 时间

装饰器其实就是一个以函数作为参数并返回一个替换函数的可执行函数。在不改动原函数代码的情况下,为其增加新的功能。wapper(*args,**kw)函数

写一个简单的装饰器

def my_decorator(func):

    def wrapper():
        print "log debug: start call {}".format(func.__name__)
        func()
        print "log debug: end call {}".format(func.__name__)

    return wrapper()

def do_something():
    print "do something"

my_decorator(do_something)


output:
log debug: start call do_something
do something
log debug: end call do_something

这里的函数 my_decorator() 就是一个装饰器,它把真正需要执行的函数 do_something() 包裹在其中,并且改变了它的行为,但是原函数 do_something() 不变。

另一种 简单 优雅的表示方法

def my_decorator(func):

    def wrapper(*arg, **kw):
        print "log debug: start call {}".format(func.__name__)
        func(*arg, **kw)
        print "log debug: end call {}".format(func.__name__)

    return wrapper

@my_decorator
def do_something(name):
    print "do something: name is {}".format(name)

do_something(name="test")

output:
log debug: start call do_something
do something: name is test
log debug: end call do_something

这里使用了@ 语法糖 @my_decoretor 相当于my_decorator(do_something)

类装饰器

class LogTime(object):

    def __call__(self, func):

        def _log(*args, **kwargs):
            print("log time")
            func(*args, **kwargs)

        return _log

# @timeout(5)
# @calculate_time(retrt_time=10)
@LogTime()
def appxx():
    """
    业务应用
    """
    return
    try:
        time.slepp(2)
    except Exception as e:
        print(e)


appxx()

给装饰器穿参数

类装饰器

class LogTime(object):

    def __init__(self, name):
        self.name = name
    def __call__(self, func):

        def _log(*args, **kwargs):
            print("log time")
            print("name is {}".format(self.name))
            func(*args, **kwargs)

        return _log


@LogTime("test")
def appxx():
    """
    业务应用
    """
    return
    try:
        time.slepp(2)
    except Exception as e:
        print(e)


appxx()

函数装饰器 传参数

def calculate_time(retrt_time):

    def decorator(func):
        def wrapper(*args, **kwargs):
            print(retrt_time)
            currnt_no = 1
            while currnt_no <= retrt_time:
                currnt_no += 1
                try:
                    func(*args, **kwargs)
                    break
                except Exception as e:
                    print(e)

        return wrapper
    return decorator

@calculate_time(retrt_time=3)
def appxx():
    """
    业务应用
    """
    return
    try:
        time.slepp(2)
    except Exception as e:
        print(e)


appxx()

装饰器中实现超时机制


import signal
from functools import wraps


def calculate_time(retrt_time):
    def decorator(func):

        @wraps(func)
        def wrapper(*args, **kwargs):
            print(retrt_time)
            currnt_no = 1

            def handler(arg1, arg2):
                raise Exception("time out")
                pass

            # 将SIGALRM信号与一个处理函数handler关联起来。当SIGALRM信号被触发时,handler函数就会被调用
            signal.signal(signal.SIGALRM, handler)
            # 1秒后发送SIGALRM信号
            signal.alarm(1)

            while currnt_no <= retrt_time:
                currnt_no += 1
                try:
                    func(*args, **kwargs)
                    break
                except Exception as e:
                    print(e)

        return wrapper

    return decorator


@calculate_time(retrt_time=3)
def appxx():
    """
    业务应用
    """
    # return
    try:
        time.sleep(2)
    except Exception as e:
        print(e)


appxx()