装饰器

先来看一个例子,一个函数f1接收另一个函数f2作为参数,并将该参数f2返回给f2:

def deco(func):
print("before myfunc() called.")
func()
print("after myfunc() called.")
return func def myfunc():
print("myfunc() called.") myfunc = deco(myfunc) myfunc() myfunc()

可以使用装饰器(Decorator)语法糖来简化代码:

def deco(func):
print("before myfunc() called.")
func()
print("after myfunc() called.")
return func @deco
def myfunc():
print("myfunc() called.") myfunc() myfunc()

跟上面的代码完全一样,也就是说在定义一个函数(比如foo)的时候,加上@deco,就等同于:foo = deco(foo)

简单的看上面的代码似乎没什么价值,无非就是在Decorator中接收一个函数作为参数,并返回给作为参数的函数本身。

但如果我们在Decorator中内嵌定义一个新的函数,并将这个新的函数返回给作为参数的函数,那就不一样了,例如:

def deco(func):
def _newfunc():
print("before myfunc() called.")
func()
print("after myfunc() called.")
# 不需要返回func,实际上应返回原函数的返回值
return _newfunc @deco
def myfunc():
print("myfunc() called.")
return 'ok' myfunc()

在这里,myfunc()函数永久的失去了,后续调用myfunc(),真正调用的其实是在Decorator中返回的函数。

可见,Decorator实际上就是一个函数,一个用来包装函数的函数,返回一个修改之后的函数对象,将其重新赋值原来的标识符,并永久丧失对原始函数对象的访问。

Decorator是在函数之上的修饰,这些修饰仅是当声明一个函数或者方法的时候,才会应用的额外调用。


装饰带参数的函数

上面的例子Decorator装饰的参数都是无参的,下面来看如何装饰带参数的函数,

def deco(func):
def _newfunc(a, b):
print("before myfunc() called.")
ret = func(a, b)
print("after myfunc() called. result: %s" % ret)
return ret
return _newfunc @deco
def myfunc(a, b):
print("myfunc(%s,%s) called." % (a, b))
return a + b myfunc(1, 2)

如果被装饰函数的参数个数不确定呢,即可变参数的情况:

def deco(func):
def _newfunc(*args, **kwargs):
print("before %s called." % func.__name__)
ret = func(*args, **kwargs)
print("after %s called. result: %s" % (func.__name__, ret))
return ret
return _newfunc @deco
def myfunc(a, b=8, c=1):
print("myfunc2(%s,%s,%s) called." % (a, b, c))
return a+b+c myfunc(1)
myfunc(1, 4)
myfunc(1, 10, 9)

只要在装饰器中的内嵌函数使用可变参数列表(*args、**kwargs)即可。


装饰器自身带参数

这种情况需要嵌套两层函数:

def deco(arg):
def _deco(func):
def _newfunc():
print("before %s called [%s]." % (func.__name__, arg))
func()
print("after %s called [%s]." % (func.__name__, arg))
return _newfunc
return _deco @deco("mymodule")
def myfunc():
print("myfunc() called.") myfunc()

如上面的例子,执行myfunc 函数实际上是执行:deco("mymodule")(myfunc) ,deco("mymodule") 返回的是_deco函数,再调用该函数_deco(myfunc),最终返回的是_newfunc函数。

函数也是对象,有__name__属性,如果执行 myfunc.__name__ 语句,会发现返回的是 "_newfunc",如果要保留被装饰函数的原来名字,可以在装饰器中加入一句:@functools.wraps(func)

def deco(arg):
def _deco(func):
@functools.wraps(func)
def _newfunc():
print("before %s called [%s]." % (func.__name__, arg))
func()
print("after %s called [%s]." % (func.__name__, arg))
return _newfunc
return _deco

如果装饰器的参数是类类型:

class locker:
def __init__(self):
print("locker.__init__() should be not called.") @staticmethod
def acquire():
print("locker.acquire() called.(这是静态方法)") @staticmethod
def release():
print(" locker.release() called.(不需要对象实例)") def deco(cls):
'''cls 必须实现acquire和release静态方法'''
def _deco(func):
def __deco():
print("before %s called [%s]." % (func.__name__, cls))
cls.acquire()
try:
return func()
finally:
cls.release()
return __deco
return _deco @deco(locker)
def myfunc():
print(" myfunc() called.") myfunc()

同时使用多个装饰器

class mylocker:
def __init__(self):
print("mylocker.__init__() called.") @staticmethod
def acquire():
print("mylocker.acquire() called.") @staticmethod
def unlock():
print(" mylocker.unlock() called.") class lockerex(mylocker):
@staticmethod
def acquire():
print("lockerex.acquire() called.") @staticmethod
def unlock():
print(" lockerex.unlock() called.") def lockhelper(cls):
'''cls 必须实现acquire和release静态方法'''
def _deco(func):
def __deco(*args, **kwargs):
print("before %s called." % func.__name__)
cls.acquire()
try:
return func(*args, **kwargs)
finally:
cls.unlock()
return __deco
return _deco class example:
@lockhelper(mylocker)
def myfunc(self):
print(" myfunc() called.") @lockhelper(mylocker)
@lockhelper(lockerex)
def myfunc2(self, a, b):
print(" myfunc2() called.")
return a + b a = example()
a.myfunc()
print(a.myfunc())
print(a.myfunc2(1, 2))
print(a.myfunc2(3, 4))

python之装饰器【转】的更多相关文章

  1. Python各式装饰器

    Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义. 一.函数式装饰器:装饰器本身是一个函数. 1.装饰函数:被装饰对象是一个函数 [1]装饰器无参数: a.被装饰对象无参数: ...

  2. Python札记 -- 装饰器补充

    本随笔是对Python札记 -- 装饰器的一些补充. 使用装饰器的时候,被装饰函数的一些属性会丢失,比如如下代码: #!/usr/bin/env python def deco(func): def ...

  3. python基础——装饰器

    python基础——装饰器 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数. >>> def now(): ... print('2015-3-25 ...

  4. 【转】详解Python的装饰器

    原文链接:http://python.jobbole.com/86717/ Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现 ...

  5. 两个实用的Python的装饰器

    两个实用的Python的装饰器 超时函数 这个函数的作用在于可以给任意可能会hang住的函数添加超时功能,这个功能在编写外部API调用 .网络爬虫.数据库查询的时候特别有用 timeout装饰器的代码 ...

  6. python 基础——装饰器

    python 的装饰器,其实用到了以下几个语言特点: 1. 一切皆对象 2. 函数可以嵌套定义 3. 闭包,可以延长变量作用域 4. *args 和 **kwargs 可变参数 第1点,一切皆对象,包 ...

  7. 理解Python中的装饰器//这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档

    转自:http://www.cnblogs.com/rollenholt/archive/2012/05/02/2479833.html 这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档 ...

  8. python基础—装饰器

    python基础-装饰器 定义:一个函数,可以接受一个函数作为参数,对该函数进行一些包装,不改变函数的本身. def foo(): return 123 a=foo(); b=foo; print(a ...

  9. 详解Python的装饰器

    Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye()两个函数. def sa ...

  10. 关于python的装饰器(初解)

    在python中,装饰器(decorator)是一个主要的函数,在工作中,有了装饰器简直如虎添翼,许多公司面试题也会考装饰器,而装饰器的意思又很难让人理解. python中,装饰器是一个帮函数动态增加 ...

随机推荐

  1. 【C++学习笔记】强大的算法——spfa

    spfa的定义 PFA算法的全称是:Shortest Path Faster Algorithm,用于求单源最短路,由西南交通大学段凡丁于1994年发表.当给定的图存在负边时,Dijkstra算法就无 ...

  2. SpringBoot日志输出至Logstash

    1.springboot项目pom.xml文件下添加如下配置 2.resources目录下创建logback-spring.xml文件 <?xml version="1.0" ...

  3. php同一个用户同时只能登陆一个, 后登陆者踢掉前登陆者(排他登陆)

    通常用户登陆,如果没有特别的限定, 同一个用户可以同时登陆, 今天搞了一个东西限定一个用户不能同时登陆到一个系统上, 后登陆者会把前面登陆的踢出来.(有点像QQ,同个帐号不能在多个地方同时在线, 后面 ...

  4. windows环境下安装npm、cnpm、bower

    什么是npm.cnpm.bower? 简单地说,就是帮你下载好你需要的css或者js库,而且三者功能也都是一样的.那为什么要下载这3个不同的呢?据说npm容易被墙……而cnpm是淘宝的镜像,所以通常用 ...

  5. ZendFramework-2.4 源代码 - 关于MVC - Model层

    所谓的谓词Predicate // ------ 所谓的谓词 ------ // 条件 case.3 $where = new \Zend\Db\Sql\Where(); $expression = ...

  6. x01.xiangqi: 走动棋子

    采用 pygame 写的象棋程序,目前只完成绘制棋盘与走动棋子,还没考虑规则等问题. 1. 代码: """ x01.xiangqi (c) 2019 by x01&quo ...

  7. B - Sonya and Exhibition CodeForces - 1004B (思维题)

    B. Sonya and Exhibition time limit per test 1 second memory limit per test 256 megabytes input stand ...

  8. java的类加载器体系结构和双亲委派机制

    类加载器将字节码文件加载到内存中,同时在方法区中生成对应的java.land.class对象  作为外部访问方法区的入口. 类加载器的层次结构: 引导类加载器<-------------扩展类加 ...

  9. EXCEL合并单元格快捷键暨WORD+EXCEL自定义快捷键

    最近在写测试用例时,用到合并单元格,只能点,没有快捷键,觉得很蛋疼,上网找了一下,没有直接设置其对应快捷键的方法,但有种曲线救国的方法: 一.右击功能区,选择‘自定义快速访问工具栏’   二.可以在这 ...

  10. MongoDB用PCRE正则表达式

    介绍 下面说明 PCRE 所支持的正则表达式的语法和语义.Perl 文档和很多其它书中也解说了正则表达式,有的书中有很多例子.Jeffrey Friedl 写的“Mastering Regular E ...