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

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

  一、函数装饰器:

def use_logging(func):
def wrapper(*args, **kwargs):
logging.warn("%s is running" % func.__name__)
return func(*args, **kwargs)
return wrapper def 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') @Foo
def 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

  函数

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

  该函数完成等价于:

def f(x):
"""does some math"""
return x + x * x
f = 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 wraps
def logged(func):
@wraps(func)
def with_logging(*args, **kwargs):
print func.__name__ + " was called"
return func(*args, **kwargs)
return with_logging @logged
def f(x):
"""does some math"""
return x + x * x print 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)" %x a = 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(<class '__main__.A'>,3)
>>> A.class_foo(3)
executing class_foo(<class '__main__.A'>,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 "<stdin>", line 1, in <module>
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

python装饰器的作用的更多相关文章

  1. python 装饰器的理解以及类装饰器

    python装饰器的作用就是在不改变原有函数结构的情况下给该函数增加一个新功能,就是不入侵到原来函数里面修改代码给其增加一个新功能 先看代码 def out(fn): def inner(*args, ...

  2. python装饰器(披着羊皮的狼)

    python装饰器的作用是在不改变原有函数的基础上,对函数的功能进行增加或者修改. 装饰器语法是python语言更加优美且避免很多繁琐的事情,flask中配置路由的方式便是装饰器. 首先python中 ...

  3. python装饰器中@wraps作用--修复被装饰后的函数名等属性的改变

    Python装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python的functools包中提供了一个叫wraps的de ...

  4. 关于python装饰器

    关于python装饰器,不是系统的介绍,只是说一下某些问题 1 首先了解变量作用于非常重要 2 其次要了解闭包 def logger(func): def inner(*args, **kwargs) ...

  5. 理解Python装饰器

    装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.它经常用于有切面需求的场景,比如:插入日志.性能测试.事务处理.缓存.权 ...

  6. Python装饰器由浅入深

    装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们 ...

  7. Python装饰器笔记

    DRY(Don't Repeat Yourself)原则: 一般是指在写代码的时候尽量避免重复的实现.违反DRY原则导致的坏处很容易理解,例如维护困难,修改时一旦遗漏就会产生不易察觉的问题. 一.函数 ...

  8. Python装饰器与面向切面编程

    今天来讨论一下装饰器.装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数 ...

  9. python装饰器总结

    一.装饰器是什么 python的装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.简单的说装饰器就是一个用来返回函数的函数 ...

随机推荐

  1. 【R】多元线性回归

    R中的线性回归函数比较简单,就是lm(),比较复杂的是对线性模型的诊断和调整.这里结合Statistical Learning和杜克大学的Data Analysis and Statistical I ...

  2. 【bzoj4010】[HNOI2015]菜肴制作 拓扑排序+堆

    题目描述 给你一张有向图,问:编号-位置序(即每个编号的位置对应的序列)最小(例如1优先出现在前面,1位置相同的2优先出现在前面,以此类推)的拓扑序是什么? 输入 第一行是一个正整数D,表示数据组数. ...

  3. P4342 [IOI1998]Polygon

    题意翻译 题目可能有些许修改,但大意一致 多边形是一个玩家在一个有n个顶点的多边形上的游戏,如图所示,其中n=4.每个顶点用整数标记,每个边用符号+(加)或符号*(乘积)标记. 第一步,删除其中一条边 ...

  4. 用iFrame模拟Ajax上传文件

    前段时间在解决ajax上传文件时折腾了好一阵.直接用$.post上传文本信息肯定是没有问题的.但是$.post直接上传图片是不可行的. 后来看到网上的一些解决方案,有现成的ajax上传文件的封装的方法 ...

  5. spring in action 学习笔记十:用@PropertySource避免注入外部属性的值硬代码化

    @PropertySource的写法为:@PropertySource("classpath:某个.properties文件的类路径") 首先来看一下这个案例的目录结构,重点看带红 ...

  6. 身为多年的ubuntu用户。。。

    在这之前 说是多年也没有多年,事实上也就两年.. 不得不说一句,终于承受不住不稳定之重了... 个人觉得开始还是从centos开始比较好,比如说现在的我.. 之前看过的不知道在哪里的文章,谈论的是ub ...

  7. python通过SSH登陆linux并操作

    使用python通过SSH登陆linux并操作 用的昨天刚接触到的库,在windows下通过paramiko来登录linux系统并执行了几个命令,基本算是初试成功,后面会接着学习的. 代码: > ...

  8. 洛谷T8115 毁灭

    题目描述 YJC决定对入侵C国的W国军队发动毁灭性打击.将C国看成一个平面直角坐标系,W国一共有n^2个人进入了C国境内,在每一个(x,y)(1≤x,y≤n)上都有恰好一个W国人.YJC决定使用m颗核 ...

  9. 我对 aspnetpager和repeater以及查询条件的封装

    /// <summary>         /// 绑定所有图片列表         /// </summary>         /// <param name=&qu ...

  10. NOIP2011提高组

    D1T1.铺地毯 for循环 #include<iostream> #include<cstdio> #include<algorithm> using names ...