python之装饰器【转】
装饰器
先来看一个例子,一个函数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之装饰器【转】的更多相关文章
- Python各式装饰器
Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义. 一.函数式装饰器:装饰器本身是一个函数. 1.装饰函数:被装饰对象是一个函数 [1]装饰器无参数: a.被装饰对象无参数: ...
- Python札记 -- 装饰器补充
本随笔是对Python札记 -- 装饰器的一些补充. 使用装饰器的时候,被装饰函数的一些属性会丢失,比如如下代码: #!/usr/bin/env python def deco(func): def ...
- python基础——装饰器
python基础——装饰器 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数. >>> def now(): ... print('2015-3-25 ...
- 【转】详解Python的装饰器
原文链接:http://python.jobbole.com/86717/ Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现 ...
- 两个实用的Python的装饰器
两个实用的Python的装饰器 超时函数 这个函数的作用在于可以给任意可能会hang住的函数添加超时功能,这个功能在编写外部API调用 .网络爬虫.数据库查询的时候特别有用 timeout装饰器的代码 ...
- python 基础——装饰器
python 的装饰器,其实用到了以下几个语言特点: 1. 一切皆对象 2. 函数可以嵌套定义 3. 闭包,可以延长变量作用域 4. *args 和 **kwargs 可变参数 第1点,一切皆对象,包 ...
- 理解Python中的装饰器//这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档
转自:http://www.cnblogs.com/rollenholt/archive/2012/05/02/2479833.html 这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档 ...
- python基础—装饰器
python基础-装饰器 定义:一个函数,可以接受一个函数作为参数,对该函数进行一些包装,不改变函数的本身. def foo(): return 123 a=foo(); b=foo; print(a ...
- 详解Python的装饰器
Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye()两个函数. def sa ...
- 关于python的装饰器(初解)
在python中,装饰器(decorator)是一个主要的函数,在工作中,有了装饰器简直如虎添翼,许多公司面试题也会考装饰器,而装饰器的意思又很难让人理解. python中,装饰器是一个帮函数动态增加 ...
随机推荐
- runtime运行时,类、对象、isa指针
先查看一段OC源码,关于类的定义: /// An opaque type that represents an Objective-C class. typedef struct objc_class ...
- 牛客小白月赛5 G 异或(xor) 【找规律】
题目链接: https://www.nowcoder.com/acm/contest/135/g 题目描述 从前,Apojacsleam家的水族箱里,养了一群热带鱼. 在这几条热带鱼里,Apojacs ...
- scrapy 圣墟
# -*- coding: utf-8 -*- import scrapy from sx.items import SxItem class SkSpider(scrapy.Spider): nam ...
- Java 替换word文档文字,指定位置插入图片
先说下 需要的依赖包 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ex ...
- Oracle - 存储过程、函数、包的使用练习-雇员
--存储过程范例:得到雇员表 emp 的记录数 begin --说明:若过程中要向外抛异常,请使用 exception when others then raise; 这个抛出的异常在程序里是可以捕获 ...
- asp.net 中 UpdataPanel 的使用注意点
1. 在UpdataPanel 前必须加上asp:ScriptManager的控件,保证页面能够正常显示
- centos下修改docker连接docker_host默认方式为tls方式
1.安装docker,请参考官网文档 centos下安装docker 2.安装完成应该可以使用docker的各种命令连接docker host.docker host运行在本机上,但与localhos ...
- 怎么选取训练神经网络时的Batch size?
怎么选取训练神经网络时的Batch size? - 知乎 https://www.zhihu.com/question/61607442 深度学习中的batch的大小对学习效果有何影响? - 知乎 h ...
- music21 关联 MuseScore 和 Lilypond
在python安装 music21后,需要关联 musescore 或 lilypond 才能可以用图形化的形式看到 乐谱. 因此 在安装 music21后,需要配置环境变量,yvivid 在 mus ...
- hdu1950Bridging signals(求最长上升自序列nlogn算法)
Bridging signals Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...