码迷,mamicode.com
首页 > 编程语言 > 详细

python3.5.2之装饰器(1)

时间:2016-08-05 21:42:04      阅读:259      评论:0      收藏:0      [点我收藏+]

标签:装饰器

 一、本次实验环境

在腾讯云虚拟主机centos7上配置pyenv多版本python管理器,并安装交互式web编辑器jupyter,python版本为3.5.2。

 二、装饰器:

装饰器的本质是一个函数,接收一个函数作为参数,并且返回一个函数
带参数的装饰器是一个函数,返回一个装饰器
带参数的装饰器最多允许一层,timeit()()(不允许)

 

在python中,一个函数可以作为参数传递给另外一个函数,还可返回一个函数(不了解此请看高阶函数)因此,我们可以把一个函数传递给另一个函数后,在这个被传递的函数的外部补充一些操作(装饰),而后把这个额外添加了补充装饰的函数得新return回来,装饰器也是高阶函数的一种。

 

1、不带参数的装饰器:

#装饰器的本质是一个函数,接收一个函数作为参数,并且返回一个函数
#带参数的装饰器是一个函数,返回一个装饰器
#带参数的装饰器最多允许一层@timeit()()(不允许)
#@abs
#@all
#@callable
#def func():
#    pass
#abs(all(callable(func)))
def fun(fn):#接收一函数作为参数
    print(‘numner1‘)
    def wrap(*args,**kwargs):#接收函数的参数
        print(‘number2‘)
        ret = fn(*args,**kwargs)#被装饰的函数
        print(‘number3‘)
        return ret
    print(‘number4‘)
    return wrap
@fun
def func(*args,**kwargs):
    print(args)
    print(‘run‘)
    return args
z = func(1,2,3,4,5,6)
print(z)
#等价于
def func(*args,**kwargs):
    print(args)
    print(‘run‘)
    return args
z = fun(func)
f = z(1,2,3,4,5,6)
print(f)
#等价于
def func(*args,**kwargs):
    print(args)
    print(‘run‘)
    return args
z = fun(func)(1,2,3,4,5,6)
print(z)
print(‘############################################‘)
#func被多个装饰器装饰
@fun
@fun
@fun
def func(*args,**kwargs):
    print(args)
    print(‘run‘)
    return args
z = func(1,2,3,4,5,6)
print(z)
#等价于
print(‘############################################‘)
def func(*args,**kwargs):
    print(args)
    print(‘run‘)
    return args
z = fun(fun(fun(func)))(1,2,3,4,5,6)
print(z)
#根据结果,先执行最外层函数与次内层函数的语句,然后执行次内层与次次内层的语句
#以此类推到最内层函数时,即为被装饰的函数func

 

2、带参数的装饰器:

#(1)、判断一个用户是否在允许列表中,若在,则执行fn功能函数
from functools import wraps 
def check(allows):
    def dec(fn):
        @wraps(fn)#这里的@wraps(fn)意思是装饰wrap函数,将fn作为参数,
        def wrap(username,*args,**kwargs):#此时函数wrap函数的方法(wrap.__name__等)即为fn.__name__
            if username in allows:
                return fn(username,*args,**kwargs)
            return ‘not allow‘#抛出异常 
        return wrap
    return dec
@check([‘i‘,‘you‘,‘he‘])
def test(username):
    print(‘congratulations‘)
result = test(‘he‘)
print(result)
#等价于
def test(username):
    print(‘congratulations‘)
result = check([‘i‘,‘you‘,‘he‘])(test)(‘she‘)#高阶函数理解了,这里也就多了一层函数,而这个函数接收了一个参数
print(result)

 

#(2)、default_user
from functools import wraps
def inject_user(default_user):
    def inject(fn):
        @wraps(fn)
        def wrap(*args,**kwargs):
            if ‘user‘ not in kwargs.keys():
                kwargs[‘user‘] = default_user
            ret = fn(*args,**kwargs)#拿到我们想要的结果
            return ret
        return wrap
    return  inject
@inject_user(‘comyn‘)
def do_something(*args,**kwargs):
    print(kwargs.get(‘user‘))
    return 23
ret = do_something(user=‘magedu‘)
print(ret)

 

 3、装饰器的应用:

(1)、装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能
(2)、装饰器经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景
(3)、装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用
(4)、概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
#(1)、cache缓存
import time
from functools import wraps
from functools import lru_cache#python内置的cache装饰器
def cache(instance):#instance为cache接口的封装
    def dec(fn):
        @wraps(fn)
        def wrap(*args,**kwargs):
            #key =>fn_name::params
            pos = ‘,‘.join((str(x) for x in args))
            kw = ‘,‘.join(‘{}={}‘.format(k,v) for k,v in sorted(kwargs.items()))
            key = ‘{}::{}::{}‘.format(fn.__name__,pos,kw)#生成key
            ret = instance.get(key)#判断key是否在cache中
            print(key)
            print(ret)
            if ret is not None:#从cache中得到
                return ret
            ret = fn(*args,**kwargs)#这里我们也可以装饰一个到腾讯云mysql数据库取数据的函数
            instance.set(key,ret)#放进缓存(这里指DictCache)
            return ret
        return wrap
    return dec
class DictCache:#这里用一个字典来作为缓存,腾讯云缓存也可以
    def __init__(self):
        self.cache = dict()
    def get(self,key):
        return self.cache.get(key)
    def set(self,key,value):
        self.cache[key] = value
    def __str__(self):
        return str(self.cache)
    def __repr__(self):
        return repr(self.cache)
if __name__ == ‘__main__‘:
    cache_instance = DictCache()#缓存实例可以是腾讯云memcached,redis,mongodb
    @cache(cache_instance)
    def long_time_fun(x):
        time.sleep(x)
        return x
    x = long_time_fun(3)
    print(x)
    y = long_time_fun(3)
    print(y)

    #拿标准库来实现
    @lru_cache()#具有换出策略lru
    def time_fun(x):
        time.sleep(x)
        return x
    x = time_fun(3)
    print(x)
    y = time_fun(3)
    print(y)

 

 

#(2)、监控
import logging
import time
from functools import wraps
def mertic(prefix,instance):#instance为各种不同类型监控平台的对象,
    def timeit(fn):# prefix为监控对象的前缀,属于哪个APP、主机的一个标记
        @wraps(fn)
        def wrap(*args,**kwargs):
            start = time.time()
            ret = fn(*args,**kwargs)#取数据
            key = ‘{}.{}.{}‘.format(prefix,fn.__module__,fn.__name__)
            instance.send(key,time.time()-start)#发送到监控处理的地方,比如statsd上
            return ret
        return wrap
    return timeit
#influxdb,grafana展示
class LoggingMetric:
    def send(self,key,value):
        logging.warning(‘{}=>{}‘.format(key,value))

@mertic(prefix=‘mysql‘,instance=LoggingMetric())
def long_time_fun(x):
    time.sleep(x)
    return x
print(long_time_fun(1))

 

(3)、身份验证(4)、路由

 未完待续!!!请看python3.5.2之装饰器(2)

 

 

 

本文出自 “11727697” 博客,请务必保留此出处http://11737697.blog.51cto.com/11727697/1834858

python3.5.2之装饰器(1)

标签:装饰器

原文地址:http://11737697.blog.51cto.com/11727697/1834858

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!