Python装饰器

装饰器表现形式1.函数装饰器编写自定义装饰器有许多方法,但最简单的方法是编写一个函数,返回包装原始函数调用的一个子函数例1:>>>[DEBUG]:entersay_he

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

Python装饰器此处内容已经被作者隐藏,请输入验证码查看内容
验证码:
请关注本站微信公众号,回复“”,获取验证码。在微信里搜索“”或者“”或者微信扫描右侧二维码都可以关注本站微信公众号。

  Python装饰器的作用是使函数包装和方法包装变得更容易阅读和理解,最常见的就是@staticmethod和@classmethod,下面将从装饰器的表现形式和常用装饰器模式两方面进行描述和总结,若有不正确之处望大家指出。

装饰器表现形式

1. 函数装饰器

  编写自定义装饰器有许多方法,但最简单的方法是编写一个函数,返回包装原始函数调用的一个子函数

  例1:

#coding=utf-8

def debug(func):
    def wrapper(*agrs, **kwargs):
        '''包装函数内部文档''' 
        print ("[DEBUG]:enter %s()--%s" %(func.__name__, *agrs))
        return func(*agrs, **kwargs)
    return wrapper
@debug
def say_hello(parm): ''' 提供函数文档字符串''' print ("say_hello") if __name__ == "__main__": say_hello("Python") print ("原始函数名:%s" %(say_hello.__name__)) print ("函数文档字符串:%s" %(say_hello.__doc__))

>>> [DEBUG]:enter say_hello()–Python
>>> say_hello
>>> 原始函数名:wrapper
>>> 函数文档字符串:包装函数内部文档

  例2:

#coding=utf-8

from functools import wraps

def debug(func):
    @wraps(func)
    def wrapper(*agrs, **kwargs):
        '''包装函数内部文档''' 
        print ("[DEBUG]:enter %s()--%s" %(func.__name__, *agrs))
        return func(*agrs, **kwargs)
    return wrapper

@debug
def say_hello(parm):
    ''' 提供函数文档字符串'''
    print ("say_hello")
    
if __name__ == "__main__":
    say_hello("Python")
    print ("原始函数名:%s" %(say_hello.__name__))
    print ("函数文档字符串:%s" %(say_hello.__doc__))

>>> [DEBUG]:enter say_hello()–Python
>>> say_hello
>>> 原始函数名:say_hello
>>> 函数文档字符串: 提供函数文档字符串

注意例1与例2的区别,也是使用装饰器的常用错误,在使用装饰器时不保存函数元数据(文档字符串和原始函数名)

2. 类作为装饰器

  虽然装饰器几乎总是可以用函数来实现,但如果装饰器需要复杂的参数化或者依赖特定状态的话,使用自定义类进行封装可能会更好

#coding=utf-8

from functools import wraps

class debug:
    def __init__(self, func):
        self.func = func

    def __call__(self, *argv, **kwargv):
        '''包装函数内部文档'''
        print ("[DEBUG]:enter %s()--%s" %(self.func.__name__, *argv))
        self.func(*argv, **kwargv)

def say_hello(something):
    ''' 提供函数文档字符串 '''
    print ("say_hello", something)
    
if __name__ == "__main__":
    De = debug(say_hello)
    De("Python")
    print ("原始函数名:%s" %(say_hello.__name__))
    print ("函数文档字符串:%s" %(say_hello.__doc__))

>>> [DEBUG]:enter say_hello()–Python
>>> say_hello Python
>>> 原始函数名:say_hello
>>> 函数文档字符串: 提供函数文档字符串

3. 参数化装饰器

  在实际代码中通常需要使用参数化的装饰器,比如次数、类型判断等,下面是一个简单的装饰器示例,给定重复次数,每次被调用时都会重复执行被装饰函数

#coding=utf-8

from functools import wraps

#参数化装饰器
def repeat(number=3):
    def debug(func):
        @wraps(func)
        def wrapper(*argv, **kwargv):
            '''包装函数内部文档'''
            for _ in range(number):
                print ("[DUBEG]:enter %s()--%s" %(func.__name__, *argv))
                result = func(*argv, **kwargv)
            return result
        return wrapper 
    return debug    

@repeat(2)
def say_hello(*agrv, **kwargv):
    '''提供函数文档字符串'''
    print ("say_hello")
    
if __name__ == "__main__":  
    say_hello("Python")
    print ("原始函数名:%s" %(say_hello.__name__))
    print ("函数文档字符串:%s" %(say_hello.__doc__))

>>> [DUBEG]:enter say_hello()–Python
>>> say_hello
>>> [DUBEG]:enter say_hello()–Python
>>> say_hello
>>> 原始函数名:say_hello
>>> 函数文档字符串:提供函数文档字符串

4. 装饰器装饰类

  和装饰一个函数类似,也可以写一个函数来装饰类,用来向类中添加功能,基本原则一致,装饰器是一个函数或是一个可调用对象,它接受一个类作为参数,返回一个类作为返回值

#coding = utf-8

def decoratortest(cls):
    print ("{0.__class__.__qualname__}".format(cls))
    return cls

@decoratortest
class testclass:
    def __init__(self, value):
        self.value = value

    def __repr__(self):
        return "{0}:88".format(self)    

if __name__ == "__main__":
 
    t = testclass(88)

常用装饰器模式

1. 参数检查

  将函数注册到全局字典中,并将其参数和返回值保存在一个类型列表中,并对参数类型进行检测

#coding=utf-8

'''将函数注册到全局字典中,并将其参数和返回值保存在一个类型列表中'''

funname = {}
def parmcheck(in_= (type(None),), out_ =(type(None), )):
    def fun1(func):
        func_name = func.__name__
        print ("funname:%s" %(func_name))
        funname[func.__name__] = (in_, out_)
        def checkType(elements, types):
            '''用来检查参数类型的子函数'''
            if len(elements) != len(types):
                raise TypeError("Parm count is wrong!")
            li = zip(elements, types)
            typed = enumerate(li)
            for index,couple in typed:
                argv, intype = couple
                if isinstance(argv, intype):
                    print ("parm(%s) and type(%s)are all right" %(argv, intype))
                    continue
                raise TypeError("argv %d should be %s" %(argv, intype))    
                
        def decoratorfun(*argv):
            #types = [type(i) for i in range(len(argv))]
            #checkType(argv, types)
            checkType(argv, in_)
            res = func(*argv)
            #检查输出内容
            if type(res) not in (tuple, list):
                checkable_res = (res, )
            else:
                checkable_res = res
            checkType(checkable_res, out_)    
        return decoratorfun
    return fun1    
             
@parmcheck((int,int)) 
def meth1(a,b):
    print ("received:%d,%d" %(a, b))

if __name__=="__main__":
    meth1(1,2)
    print (funname)

>>> funname:meth1
>>> parm(1) and type(<class ‘int’>)are all right
>>> parm(2) and type(<class ‘int’>)are all right
>>> received:1,2
>>> parm(None) and type(<class ‘NoneType’>)are all right
>>> {‘meth1’: ((<class ‘int’>, <class ‘int’>), (<class ‘NoneType’>,))}

注意zip、enumerate、解包、isinstance方法的使用

2. 缓存

  缓存装饰器与参数检查十分相似,它的重点是关注那些内部状态不会影响输出的函数,每组参数都可以连接到唯一的结果

#coding = utf-8

import time
import pickle
import hashlib

#全局字典
cache = {}

def is_obsolete(entry, duration):
    print (time.time() - entry["time"])
    return time.time() - entry["time"] > duration

def compute_key(func, *argv, **kwargv):
    key = pickle.dumps((func.__name__, argv, kwargv))
    return hashlib.sha1(key).hexdigest()

def memoize(duration=10):
    def _memoize(func):
        def __memoize(*argv, **kwargv):
            key = compute_key(func,*argv, **kwargv)
            if ((key in cache) and not is_obsolete(cache[key], duration)):
                print ("we got a winner")
                return cache[key]['value']    
            result = func(*argv, **kwargv)
            cache[key]={"value":result,"time":time.time()}
            return result
        return __memoize
    return _memoize    

@memoize(3)
def fun(a,b):
    print (a+b)
    return a+b

if __name__=="__main__":
    fun(2,3)
    fun(2,2)
    fun(2,3)
    print (cache)
        

>>> 5
>>> 4
>>> 0.0
>>> we got a winner
>>> {‘a99634a4e619a2ad129df1b51002a8c0cb9cca2b’: {‘value’: 5, ‘time’: 1518243058.456
>>> 425}, ‘99683ddc4e22fd3f37e473de5d61699a5c27c2c6’: {‘value’: 4, ‘time’: 151824305
>>> 8.456425}}

3. 代理

  代理装饰器使用全局机制来标记和注册函数。比如一个根据当前用户来保护代码访问的安全层可以使用集中式检查器和相关的可调用对象要求的权限来访问,这一模型常用于Python Web框架中,用于定义法布类的安全性

4. 上下文提供者

   上下文装饰器确保函数可以允许在正确的上下文中,比如临界资源的使用

#coding=utf-8

from threading import RLock

lock = RLock()

def synchronized(func):
    def _synchronized(*argv, **kdargv):
        lock.require()
        try:
            return func(*argv, **kdargv)
        except:
            print ("fun error!!!")
        finally:
            lock.release()
    return _synchronized    

上下文装饰器通常会被上下文管理器with语句代替

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/120210.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • QTabWidget的样式「建议收藏」

    QTabWidget的样式「建议收藏」Tab标签所在行的样式QTabWidget::tab-bar{alignment:left;top:3px;left:5px;right:5px;}设置QTabWidget的Tab标签下面窗格的样式QTabWidget#tabwidget_DevMang::pane{border-top:3pxsolidblack;border-…

  • Unity Shader-描边效果[通俗易懂]

    简介描边效果是游戏里面非常常用的一种效果,一般在选中物体或者NPC的时候,被选中的对象就会显示描边效果。比如最近又跑回去玩了玩《剑灵》,虽然出了三年了,在现在的网游里面画面仍然算很好的。还有就是最常见的LOL中的塔,选中时就会看到很明显的描边效果:

  • 60mph和kmh换算_100mph等于多少kmh

    60mph和kmh换算_100mph等于多少kmh等于163.93公里每小时,Mph是属于英国的速度换算率,和我国所使用的Km/h有所区分,我国使用的这种方式为公制的速度换算率,而在美国、英国以及一些英联邦国家,所采用的计算速度方式,都是使用的mph。什么是MPH就是以一个速度计量单位,能够表示出每小时多少英里,也就是我们在行驶车辆的时候,车辆所行驶的速度,会被称为多少迈,按照换算比率,一迈等于1.609344千米每小时。全称为mileper…

  • centos7安装python3.6_centos7一键安装python3

    centos7安装python3.6_centos7一键安装python3centos7安装Python3安装Python3安装Python31.安装wget(如已经存在,忽略此步)yum-yinstallwget2.下载python3源码包wgethttps://www.python.org/ftp/python/3.6.6/Python-3.6.6.tgz3.下载python3编译的依赖包yuminstall-ygccpatchlibffi-develpython-develzlib-develbzip2-develope

  • pycharm安装教程2020.3.4_python安装步骤

    pycharm安装教程2020.3.4_python安装步骤第一步安装解释器,第二步安装pycharm1第一步安装解释器1.1什么是解释器:??就是将Python程序翻译成为计算机可以识别的01代码1.2安装解释器:解释器安装地址:https://www.python.org/downloads/release/python-372根据自己的操作系统安装适配的解释器:这里以Windows为例注意安装的时候我们需要需注意吧解释器添加到环境变量里面双击开始安装勾选addpythontopath,如果安装的时候没有勾选,请安装结束以后按

  • c中截取字符串(java字符串replace用法)

    C几种截取字符串的方法(splitSubstringReplaceremove)

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号