浙江诚峰建设工程有限公司网站,新站网站收录减少,做网站客户怎么找,江阴外贸公司排名文章先由stackoverflow上面的一个问题引起吧#xff0c;如果使用如下的代码#xff1a; makebold
makeitalic
def say():return Hello 打印出如下的输出#xff1a; biHelloi/b 你会怎么做#xff1f;最后给出的答案是#x…文章先由stackoverflow上面的一个问题引起吧如果使用如下的代码 makebold
makeitalic
def say():return Hello 打印出如下的输出 biHelloi/b 你会怎么做最后给出的答案是 def makebold(fn):def wrapped():return b fn() /breturn wrappeddef makeitalic(fn):def wrapped():return i fn() /ireturn wrappedmakebold
makeitalic
def hello():return hello worldprint hello() ## 返回 bihello world/i/b 现在我们来看看如何从一些最基础的方式来理解Python的装饰器。英文讨论参考 Here 。1.1. 需求是怎么来的 装饰器是一个很著名的设计模式经常被用于有切面需求的场景较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计有了装饰器我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲装饰器的作用就是为已经存在的对象添加额外的功能。装饰器的定义很是抽象我们来看一个小例子。 def foo():print in foo()
foo() 这是一个很无聊的函数没错。但是突然有一个更无聊的人我们称呼他为B君说我想看看执行这个函数用了多长时间好吧那么我们可以这样做 import time
def foo():start time.clock()print in foo()end time.clock()print used:, end - startfoo() 很好功能看起来无懈可击。可是蛋疼的B君此刻突然不想看这个函数了他对另一个叫foo2的函数产生了更浓厚的兴趣。 怎么办呢如果把以上新增加的代码复制到foo2里这就犯了大忌了~复制什么的难道不是最讨厌了么而且如果B君继续看了其他的函数呢 1.2. 以不变应万变是变也 还记得吗函数在Python中是一等公民那么我们可以考虑重新定义一个函数timeit将foo的引用传递给他然后在timeit中调用foo并进行计时这样我们就达到了不改动foo定义的目的而且不论B君看了多少个函数我们都不用去修改函数定义了 import timedef foo():print in foo()def timeit(func):start time.clock()func()end time.clock()print used:, end - starttimeit(foo) 看起来逻辑上并没有问题一切都很美好并且运作正常……等等我们似乎修改了调用部分的代码。原本我们是这样调用的foo()修改以后变成了timeit(foo)。这样的话如果foo在N处都被调用了你就不得不去修改这N处的代码。或者更极端的考虑其中某处调用的代码无法修改这个情况比如这个函数是你交给别人使用的。 1.3. 最大限度地少改动 既然如此我们就来想想办法不修改调用的代码如果不修改调用代码也就意味着调用foo()需要产生调用timeit(foo)的效果。我们可以想到将timeit赋值给foo但是timeit似乎带有一个参数……想办法把参数统一吧如果timeit(foo)不是直接产生调用效果而是返回一个与foo参数列表一致的函数的话……就很好办了将timeit(foo)的返回值赋值给foo然后调用foo()的代码完全不用修改 #-*- coding: UTF-8 -*-
import timedef foo():print in foo()# 定义一个计时器传入一个并返回另一个附加了计时功能的方法
def timeit(func):# 定义一个内嵌的包装函数给传入的函数加上计时功能的包装def wrapper():start time.clock()func()end time.clock()print used:, end - start# 将包装后的函数返回return wrapperfoo timeit(foo)
foo() 这样一个简易的计时器就做好了我们只需要在定义foo以后调用foo之前加上foo timeit(foo)就可以达到计时的目的这也就是装饰器的概念看起来像是foo被timeit装饰了。在在这个例子中函数进入和退出时需要计时这被称为一个横切面(Aspect)这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。与传统编程习惯的从上往下执行方式相比较而言像是在函数执行的流程中横向地插入了一段逻辑。在特定的业务领域里能减少大量重复代码。面向切面编程还有相当多的术语这里就不多做介绍感兴趣的话可以去找找相关的资料。 这个例子仅用于演示并没有考虑foo带有参数和有返回值的情况完善它的重任就交给你了 上面这段代码看起来似乎已经不能再精简了Python于是提供了一个语法糖来降低字符输入量。 import timedef timeit(func):def wrapper():start time.clock()func()end time.clock()print used:, end - startreturn wrappertimeit
def foo():print in foo()foo() 重点关注第11行的timeit在定义上加上这一行与另外写foo timeit(foo)完全等价千万不要以为有另外的魔力。除了字符输入少了一些还有一个额外的好处这样看上去更有装饰器的感觉。 1.4 最后回答前面提到的问题 # 装饰器makebold用于转换为粗体
def makebold(fn):# 结果返回该函数def wrapper():# 插入一些执行前后的代码return b fn() /breturn wrapper# 装饰器makeitalic用于转换为斜体
def makeitalic(fn):# 结果返回该函数def wrapper():# 插入一些执行前后的代码return i fn() /ireturn wrapper
# 注意顺序
makebold
makeitalic
def say():return helloprint say()
#输出: bihello/i/b# 等同于
def say():return hello
say makebold(makeitalic(say))print say()
#输出: bihello/i/b 2、装饰器的种类2.1 无参数装饰器 def deco(func):print funcreturn func
deco
def foo():pass
foo() 第一个函数deco是装饰函数它的参数就是被装饰的函数对象。我们可以在deco函数内对传入的函数对象做一番“装饰”然后返回这个对象记住一定要返回 不然外面调用foo的地方将会无函数可用。实际上此时foodeco(foo)我写了个小例子检查函数有没有说明文档 def deco_functionNeedDoc(func):if func.__doc__ None :print func, has no __doc__, its a bad habit.else:print func, :, func.__doc__, .return func
deco_functionNeedDoc
def f():print f() Do something
deco_functionNeedDoc
def g():I have a __doc__print g() Do something
f()
g() 2.2 有参数装饰器 def decomaker(arg):通常对arg会有一定的要求由于有参数的decorator函数在调用时只会使用应用时的参数而不接收被装饰的函数做为参数所以必须在其内部再创建一个函数def newDeco(func): #定义一个新的decorator函数print func, argreturn funcreturn newDeco
decomaker(deco_args)
def foo():pass
foo() 第一个函数decomaker是装饰函数它的参数是用来加强“加强装饰”的。由于此函数并非被装饰的函数对象所以在内部必须至少创建一个接受被装饰函数的函数然后返回这个对象实际上此时foodecomaker(arg)(foo)这个我还真想不出什么好例子还是见识少啊只好借用同步锁的例子了 def synchronized(lock):锁同步装饰方法lock必须实现了acquire和release方法def sync_with_lock(func):def new_func(*args, **kwargs):lock.acquire()try:return func(*args, **kwargs)finally:lock.release()new_func.func_name func.func_namenew_func.__doc__ func.__doc__return new_funcreturn sync_with_lock
synchronized(__locker)
def update(data):
更新计划任务tasks self.get_tasks()delete_task Nonefor task in tasks:if task[PLANTASK.ID] data[PLANTASK.ID]:tasks.insert(tasks.index(task), data)tasks.remove(task)delete_task taskr, msg self._refresh(tasks, delete_task)return r, msg, data[PLANTASK.ID] 调用时还是updae(data)。同时还可以将多个装饰器组合 使用注意调用顺序 synchronized(__locker)
deco_functionNeedDoc
def f():print f() Do something 2.3 内置的装饰器内置的装饰器有三个分别是staticmethod、classmethod和property作用分别是把类中定义的实例方法变成静态方法、类方法和类属性。由于模块里可以定义函数所以静态方法和类方法的用处并不是太多除非你想要完全的面向对象编程。而属性也不是不可或缺的Java没有属性也一样活得很滋润。从我个人的Python经验来看我没有使用过property使用staticmethod和classmethod的频率也非常低。 2.4 装饰器进阶 http://www.cnblogs.com/JohnABC/p/4186209.html 具体请参考: http://www.cnblogs.com/huxi/archive/2011/03/01/1967600.html 转自: http://www.open-open.com/lib/view/open1374584644558.html转载于:https://www.cnblogs.com/JohnABC/p/4091532.html