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

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. Reverse bits - 按位反转一个int型数字

    Reverse bits of a given 32 bits unsigned integer. For example, given input 43261596 (represented in ...

  2. vue.js使用props在父子组件之间传参

    本篇文章是我参考官方文档整理的,供大家参考,高手勿喷! prop 组件实例的作用域是孤立的.这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据.要让子组件使用父组件的数据,我们需要通过子 ...

  3. javaBean与Servlet学习

    1.JavaBean JavaBean将java代码单独封装成了一个处理某种业务逻辑的类,可以降低HTML与Java代码的耦合度,并且简化JSP页面,提高Java程序代码的重用性及灵活性. JavaB ...

  4. iOS上机题(附个人见解)

    ##机试题目如下 用命令行创建一个以CocoaPods管理的项目[Test-你的姓名拼音],新建3个ViewController,完成以下题目 将下面的问题在一个UITabView里面列出所有问题,单 ...

  5. Tornado session 插件 pycket 定制时间和时间续租

    功能描述:10分钟用户没有任何操作,跳转到登录页面. 分析:这个功能用session就能实现(由于pycket 的session内容是存储在memcached或者redis里面的.所以,session ...

  6. Head First 设计模式 第3章 装饰者模式

    第3章 装饰者模式 1.定义/说明 动态.透明的将职责附加到对象上(或从对象上撤销),而不影响其他对象.若要扩展功能,装饰者模式提供了比继承更富有弹性的替代方案. 2.介绍 首先让我们先来介绍一下场景 ...

  7. 再起航,我的学习笔记之JavaScript设计模式06(工厂方法模式)

    上一次已经给大家介绍了简单工厂模式,相信大家对创建型设计模式有了初步的了解,本次我将给大家介绍的是工厂方法模式. 工厂方法模式 工厂方法模式(Factory Method):通过对产品类的抽象使其创建 ...

  8. nopcommerce数据库字典

    http://www.xcode.me/open/document/nopcommercedatadict.html

  9. POJ 1182 食物链 -- 解题报告

    食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 70529   Accepted: 20875 Description ...

  10. 弱校ACM奋斗史

    看到这篇文章, 已是大三了, 我的ACM之路也即将走向终点, 感慨自己还是不够努力, 给自己的大学留下诸多遗憾. 和他们相比, 我差的就是太远了, 值得高兴的是我们学校有一个好老师-----赵靖老师, ...