装饰器和装饰器模式
装饰器模式是面向对象的一种设计模式,支持将行为动态增加到已经存在的对象上。当装饰一个对象的时候,就表示独立与其他类实例对象,为该对象扩展了新的功能。

python的装饰器不是装饰器模式的一种实现。python装饰器是在定义的时候对函数或方法增加功能,而不是在运行的时候增加。
装饰器模式可以在python中实现,但是这样做意义不大。因为python是鸭子类型风格的编程语言。鸭子类型(英语:duck typing)是动态类型的一种风格。

一个基础的装饰器

import time
import datetime def time_this(original_func):
def new_func(*args, **kwargs):
start_a = datetime.datetime.now()
x = original_func(*args, **kwargs)
end_a = datetime.datetime.now()
print("Elapsed Time = {0}".format(start_a - end_a))
return x
return new_func @time_this
def func_a(stuff):
print("i need a sleep.")
time.sleep(3) func_a(1)

运行结果:

i need a sleep.
Elapsed Time = -1 day, 23:59:56.999700

带有参数的装饰器
有时候,除了完成其装饰的函数外,还可以带上参数。这种技术常用于注册类似功能。比如:

@view_config(route_name='home',renderer='templates/mytemplate.pt')
def my_view(request):
return {'project':'hello decorators'}

假设有个应用,用户可以通过gui登录。用户和gui触发时间交互调用python函数。不同的用户有不同的权限。执行不同的函数需要不同了类型的权限。比如:

#assume these functions exist
def current_user_id():
"""
this function returns the current logged in user id, if the user is not authenticated then return None
""" def get_permissions(iUserId):
"""
returns a list of permission strings for the given user. For example ['logged_in','administrator','premium_member']
""" #we need to implment permission checking on these functions def delete_user(iUserId):
"""
delete the user with the given Id. This function is only accessable to users with administrator permissions
""" def new_game():
"""
any logged in user can start a new game
""" def premium_checkpoint():
"""
save the game progress, only accessable to premium members
"""

实现的方法之一是使用多个装饰器:

def requires_admin(func):
def ret_func(*args,**kwargs):
permissions = get_permissions(current_user_id())
if 'administrator' in permissions:
return func(*args,**kwargs)
else:
raise Exception("Not allowed")
return ret_func def requires_logged_in(func):
def ret_func(*args,**kwargs):
permissions = get_permissions(current_user_id())
if 'logged_in' in permissions:
return func(*args,**kwargs)
else:
raise Exception("Not allowed")
return ret_func def requires_premium_member(func):
def ret_func(*args,**kwargs):
permissions = get_permissions(current_user_id())
if 'premium_member' in permissions:
return func(*args,**kwargs)
else:
raise Exception("Not allowed")
return ret_func @requires_admin
def delete_user(iUserId):
"""
delete the user with the given Id. This function is only accessable to users with administrator permissions
""" @requires_logged_in
def new_game():
"""
any logged in user can start a new game
""" @requires_premium_member
def premium_checkpoint():
"""
save the game progress, only accessable to premium members
"""

但是这样的话,需要多个装饰器。如果有权限检查模块程序发生变动,就需要逐一修改装饰器。难道不可以通过一个装饰器来实现么?

答案是:有。我们需要一个返回结果是装饰器的函数。

def requires_permission(sPermission):
def decorator(func):
def decorated(*args,**kwargs):
permissions = get_permissions(current_user_id())
if sPermission in permissions:
return func(*args,**kwargs)
raise Exception("permission denied")
return decorated
return decorator def get_permissions(iUserId): #this is here so that the decorator doesn't throw NameErrors
return ['logged_in',] def current_user_id(): #ditto on the NameErrors
return 1 #and now we can decorate stuff... @requires_permission('administrator')
def delete_user(iUserId):
"""
delete the user with the given Id. This function is only accessible to users with administrator permissions
""" @requires_permission('logged_in')
def new_game():
"""
any logged in user can start a new game
""" @requires_permission('premium_member')
def premium_checkpoint():
"""
save the game progress, only accessable to premium members
"""

  

通用的装饰器代码示例:

def outer_decorator(*outer_args,**outer_kwargs):
def decorator(func):
def decorated(*args,**kwargs):
do_something(*outer_args,**outer_kwargs)
return func(*args,**kwargs)
return decorated
return decorator @outer_decorator(1,2,3)
def foo(a,b,c):
print a
print b
print c foo()

等价于:

def decorator(func):
def decorated(*args,**kwargs):
do_something(1,2,3)
return func(*args,**kwargs)
return decorated
return decorator @decorator
def foo(a,b,c):
print a
print b
print c foo()

装饰类
装饰器并不仅仅限于装饰函数,也可以装饰类。
假如我们有个类,需要完成很多重要工作,我们想计时这个类完成每项工作需要的时间。我们可以使用上面定义好的time_this:

class ImportantStuff(object):
@time_this
def do_stuff_1(self):
...
@time_this
def do_stuff_2(self):
...
@time_this
def do_stuff_3(self):
...

上面这样做是可以实现,但是要添加很多额外的代码行在类定义中。
如果我们写了很多类的方法,忘记了其中对其中个别函数进行装饰怎么办?或者如果我们不再需要计时功能呢。
可使用以下的方式进行优化:

@time_all_class_methods
class ImportantStuff:
def do_stuff_1(self):
...
def do_stuff_2(self):
...
def do_stuff_3(self):
...

上面的代码等价于:

class ImportantStuff:
def do_stuff_1(self):
...
def do_stuff_2(self):
...
def do_stuff_3(self):
... ImportantStuff = time_all_class_methods(ImportantStuff)

那么time_all_class_methods是如何工作的呢?
首先、它需要一个类作为参数,并返回一个类。返回的类的功能看起来应该和原先的importstuff类类似。这里我们可以这么做:

import datetime
import time def time_this(original_func):
print ("decorating")
def new_func(*args,**kwargs):
print("starting timer")
start = datetime.datetime.now()
x = original_func(*args,**kwargs)
end = datetime.datetime.now()
print "Elapsed Time = {0}".format(end-start)
return x
return new_func def time_all_class_methods(Cls):
class NewCls(object):
def __init__(self,*args,**kwargs):
self.oInstance = Cls(*args,**kwargs)
def __getattribute__(self,s):
"""
this is called whenever any attribute of a NewCls object is accessed. This function first tries to
get the attribute off NewCls. If it fails then it tries to fetch the attribute from self.oInstance (an
instance of the decorated class). If it manages to fetch the attribute from self.oInstance, and
the attribute is an instance method then `time_this` is applied.
"""
try:
x = super(NewCls,self).__getattribute__(s)
except AttributeError:
pass
else:
return x
x = self.oInstance.__getattribute__(s)
if type(x) == type(self.__init__): # it is an instance method
return time_this(x) # this is equivalent of just decorating the method with time_this
else:
return x
return NewCls #now lets make a dummy class to test it out on: @time_all_class_methods
class Foo(object):
def a(self):
print "entering a"
import time
time.sleep(3)
print "exiting a" oF = Foo()
oF.a()

  

python -- 装饰器的高级应用的更多相关文章

  1. Python装饰器的高级用法(翻译)

    原文地址 https://www.codementor.io/python/tutorial/advanced-use-python-decorators-class-function 介绍 我写这篇 ...

  2. Python装饰器由浅入深

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

  3. Python高级特性: 12步轻松搞定Python装饰器

    12步轻松搞定Python装饰器 通过 Python 装饰器实现DRY(不重复代码)原则:  http://python.jobbole.com/84151/   基本上一开始很难搞定python的装 ...

  4. python 装饰器 一篇就能讲清楚

    装饰器一直是我们学习python难以理解并且纠结的问题,想要弄明白装饰器,必须理解一下函数式编程概念,并且对python中函数调用语法中的特性有所了解,使用装饰器非常简单,但是写装饰器却很复杂.为了讲 ...

  5. Python第二十六天 python装饰器

    Python第二十六天 python装饰器 装饰器Python 2.4 开始提供了装饰器( decorator ),装饰器作为修改函数的一种便捷方式,为工程师编写程序提供了便利性和灵活性装饰器本质上就 ...

  6. 利用世界杯,读懂 Python 装饰器

    Python 装饰器是在面试过程高频被问到的问题,装饰器也是一个非常好用的特性, 熟练掌握装饰器会让你的编程思路更加宽广,程序也更加 pythonic. 今天就结合最近的世界杯带大家理解下装饰器. 德 ...

  7. Python装饰器探险

    关于python装饰器的理解和用法,推荐廖雪峰老师和这一篇博客以及知乎 以下代码均已手动敲过,看完本篇内容,包你装饰器小成! 装饰器实际上就是为了给某程序增添功能,但该程序已经上线或已经被使用,那么就 ...

  8. Python 装饰器入门(上)

    翻译前想说的话: 这是一篇介绍python装饰器的文章,对比之前看到的类似介绍装饰器的文章,个人认为无人可出其右,文章由浅到深,由函数介绍到装饰器的高级应用,每个介绍必有例子说明.文章太长,看完原文后 ...

  9. Python学习:11.Python装饰器讲解(二)

    回顾 上一节我们进行了Python简单装饰器的讲解,但是python的装饰器还有一部分高级的使用方式,这一节就针对python装饰器高级部分进行讲解. 为一个函数添加多个装饰器 今天,老板又交给你一个 ...

随机推荐

  1. RxSwift 系列(六) -- Mathematical and Aggregate Operators

    前言 本篇文章将要学习RxSwift中数学和集合操作符,在RxSwift中包括了: toArray reduce concat toArray 将一个Observable序列转化为一个数组,并转换为一 ...

  2. [luogu P3801] 红色的幻想乡 [线段树][树状数组]

    题目背景 蕾米莉亚的红雾异变失败后,很不甘心. 题目描述 经过上次失败后,蕾米莉亚决定再次发动红雾异变,但为了防止被灵梦退治,她决定将红雾以奇怪的阵势释放. 我们将幻想乡看做是一个n*m的方格地区,一 ...

  3. 操作系统,银行家算法模拟实现(Windows 环境 C++)

    计算机操作系统课设需要,写了两个下午的银行家算法(陷在bug里出不来耽误了很多时间),参考计算机操作系统(汤子瀛) 实现过程中不涉及难度较大的算法,仅根据银行家算法的思想和步骤进行实现.以下为详细步骤 ...

  4. 使用Publish Over SSH插件实现远程自动部署

    背景: 现场的部署环境开放外网环境困难,只有一台机器能够开发外网,应对该情况,所有的补丁文件需要直接在master机器上面生成,然后命令移动到其他的服务器上面去. 这里使用到了jenkins的Publ ...

  5. .Net 调用微信公众号扫一扫

    1.绑定域名 去微信公众号平台中设置js接口安全域名,要注意的是不填写http://, 只填写域名即可,如 www.baidu.com. 一个月只能修改三次,要谨慎填写. 2.引入JS文件 在页面中引 ...

  6. Java设计模式之模板方法设计模式(银行计息案例)

    不知道为什么,这几天对Java中的设计模式非常感兴趣,恰巧呢这几天公司的开发任务还不算太多,趁着有时间昨天又把模板方法模式深入学习了一下,做了一个客户在不同银行计息的小案例,感触颇深,今天给各位分享一 ...

  7. 【JAVASCRIPT】React学习-巧用 props 的 children 属性实现内容填充

    背景 平常写组件,经常遇到需要获取内容放入组件内部的情形. 实现方法 我们有两种实现方式 1. 自定义 props render 的时候通过获取 this.props.content 填充到组件内部 ...

  8. ECMAScript 6 学习(二)async函数

     1.什么是async函数 2.用法 2.1基本用法 3.语法 3.1返回promise对象 3.2promise状态的变化 3.3await命令 1.什么是async函数 async函数也是异步编程 ...

  9. mvc 下的 signalR使用小结

    https://my.oschina.net/u/867090/blog/123474

  10. 进阶篇之纯css+字体实现五角星(半颗星)评分

    1.前言 之前写了一篇实现五角星打分效果的demo.这个demo用来实现打分效果绰绰有余,那么有时候我们在统计评分的时候,就会有半颗星或者1/3颗星星这样的那要如何实现呢?来来来,纯字体+css实现! ...