博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python装饰器的作用
阅读量:4537 次
发布时间:2019-06-08

本文共 4823 字,大约阅读时间需要 16 分钟。

  常见装饰器;内置装饰器;类装饰器、函数装饰器、带参数的函数装饰器

  装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能

  一、函数装饰器:

def use_logging(func):    def wrapper(*args, **kwargs):        logging.warn("%s is running" % func.__name__)        return func(*args, **kwargs)    return wrapperdef bar():    print('i am bar') bar = use_logging(bar)bar() 输出: WARNING:root:bar is running i am bar

  二、带参数的函数装饰器:

def use_logging(level):    def decorator(func):        def wrapper(*args, **kwargs):            if level == "warn":                logging.warn("%s is running" % func.__name__)            return func(*args)        return wrapper    return decorator@use_logging(level="warn")def foo(name='foo'):    print("i am %s" % name)foo() 输出: WARNING:root:foo is running i am foo

  三、类装饰器:

  再来看看类装饰器,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器还可以依靠类内部的 __call__方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法

  

class Foo(object):    def __init__(self, func):        self._func = func    def __call__(self):        print ('class decorator runing')        self._func()        print ('class decorator ending')@Foodef bar():    print ('bar')bar() 输出: class decorator runing bar class decorator ending

  四、functools.wraps

  使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的docstring、__name__、参数列表,先看例子:

  装饰器

def logged(func):    def with_logging(*args, **kwargs):        print func.__name__ + " was called"        return func(*args, **kwargs)    return with_logging

  函数

@loggeddef f(x):   """does some math"""   return x + x * x

  该函数完成等价于:

def f(x):    """does some math"""    return x + x * xf = logged(f)

  不难发现,函数f被with_logging取代了,当然它的docstring,__name__就是变成了with_logging函数的信息了。

  print f.__name__    # prints 'with_logging'   print f.__doc__ # prints None

  这个问题就比较严重的,好在我们有functools.wraps,wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器函数中,这使得装饰器函数也有和原函数一样的元信息了。

from functools import wrapsdef logged(func):    @wraps(func)    def with_logging(*args, **kwargs):        print func.__name__ + " was called"        return func(*args, **kwargs)    return with_logging@loggeddef f(x):    """does some math"""    return x + x * xprint f.__name__  # prints 'f'print f.__doc__   # prints 'does some math'
五、内置装饰器

 @property 的用法参见:把类方法变成属性,可以通过类直接调用

   https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386820062641f3bcc60a4b164f8d91df476445697b9e000

 http://www.cnblogs.com/superxuezhazha/p/5793450.html

 因为Python支持高阶函数,在函数式编程中我们介绍了装饰器函数,可以用装饰器函数把 get/set 方法“装饰”成属性调用:

 

class Student(object):     def __init__(self, name, score):         self.name = name         self.__score = score     @property     def score(self):         return self.__score     @score.setter     def score(self, score):         if score < 0 or score > 100:             raise ValueError('invalid score')         self.__score = score 注意: 第一个score(self)是get方法,用@property装饰,第二个score(self, score)是set方法,用@score.setter装饰,@score.setter是前一个@property装饰后的副产品。 现在,就可以像使用属性一样设置score了:>>> s = Student('Bob', 59)>>> s.score = 60 >>> print s.score 60

 @staticmethod :静态方法

   @classmethod  :  类方法

 参考:http://www.cnblogs.com/taceywong/p/5813166.html

  

 Python其实有3类方法:

  • 静态方法(staticmethod)
  • 类方法(classmethod)
  • 实例方法(instance method)

   看一下下面的示例代码:

def foo(x):    print "executing foo(%s)" %(x)class A(object):    def foo(self,x):        print "executing foo(%s,%s)" %(self,x)    @classmethod    def class_foo(cls,x):        print "executing class_foo(%s,%s)" %(cls,x)    @staticmethod    def static_foo(x):        print "executing static_foo(%s)" %xa = A()

  在示例代码中,先理解下函数里面的selfcls。这个self和cls是对类或者实例的绑定,对于一般的函数来说我们可以这么调用foo(x),这个函数就是最常用的,它的工作和任何东西(类、实例)无关。对于实例方法,我们知道在类里每次定义方法的时候都需要绑定这个实例,就是foo(self,x),为什么要这么做呢?因为实例方法的调用离不开实例,我们需要把实例自己传给函数,调用的时候是这样的a.foo(x)(其实是foo(a,x)。类方法一样,只不过它传递的是类而不是实例,A.class_foo(x)。注意这里的self和cls可以替换别的参数,但是python的约定是这两个,尽量不要更改。

  对于静态方法其实和普通的方法一样,不需要对谁进行绑定,唯一的区别是调用时候需要使用a.static_foo(x)A.static_foo()来调用。

\ 实例方法 类方法 静态方法
a = A() a.foo(x) a.class_foo(x) a.static_foo(x)
A 不可用 A.clas_foo(x) A.static_foo(x)
 
>>> a=A()>>> a.foo(3)executing foo(<__main__.A object at 0x108117790>,3)>>> a.class_foo(3)executing class_foo(
,3)>>> A.class_foo(3)executing class_foo(
,3)>>> a.static_foo(3)executing static_foo(3)>>> A.static_foo(3)executing static_foo(3)>>> A.foo(3)Traceback (most recent call last): File "
", line 1, in
TypeError: unbound method foo() must be called with A instance as first argument (got int instance instead)>>>

 

参考:

1、https://www.zhihu.com/question/26930016

2、http://python.jobbole.com/85056/

3、http://pythoncentral.io/difference-between-staticmethod-and-classmethod-in-python/

4、http://30daydo.com/article/89

转载于:https://www.cnblogs.com/shengulong/p/7456442.html

你可能感兴趣的文章
Python 流程控制:for
查看>>
android.os.NetworkOnMainThreadException异常如何解决
查看>>
我的轮播练习
查看>>
js中index()的四种经典用法111
查看>>
vb Array.ConvertAll 泛型方法
查看>>
flask 基本配置和参数解释
查看>>
HDMI转EDP芯片NCS8803简介
查看>>
Git查看、删除、重命名远程分支和tag
查看>>
nexus4/5/6/7/9/10设备谷歌安卓5.1.1系统底包下载
查看>>
子界类型的应用
查看>>
ubuntu系统中查看本机cpu和内存信息的命令和用法
查看>>
PHP的学习--cookie和session
查看>>
es6 箭头函数
查看>>
python装饰器的作用
查看>>
[bzoj2510]弱题 (循环矩阵优化dp)
查看>>
Django Form 的主要内置字段介绍
查看>>
如何写好一个UITableView
查看>>
XML文件生成C++代码(基于rapidxml)
查看>>
写代码,更需要设计代码
查看>>
iOS:修改项目名
查看>>