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

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. 《javascript设计模式与开发实践》读书笔记之函数,this,闭包

    一.函数基本理论 function compare(val1,val2){ return val1 - val2; }var result = compare(5,10); 1,函数的定义没什么意义, ...

  2. 关于SEO的一些浅认识

    SEO的浅认识 定义描述:在百度百科上它是这样描述的--------SEO是指在了解搜索引擎自然排名机制的基础之上,对网站进行内部及外部的调整优化,改进网站在搜索引擎中关键词的自然排名,获得更多的展现 ...

  3. Unity 工作经历+近期面试经历

    由于团队解散,这最近都在找新工作机会--投简历找工作.已经面试三家了,都没拿到offer,挺失落的.把这种感受记录下来,以作后鉴. 这本质上是一篇面试经历的记录,并不是什么面试攻略,主要是给自己总结的 ...

  4. Linux shell for while 循环

    1.数字段形式for i in {1..10}do   echo $idone 2.详细列出(字符且项数不多)for File in 1 2 3 4 5 do     echo $File done ...

  5. Storm源码阅读之SpoutOutputCollector

    不得不说storm是一个特别棒的实时计算框架.为了对后文理解的方便,先说几个storm中的术语: Topology:拓扑图或者拓扑结构.在storm中它通过消息分组的分式连接Spout和Bolt节点定 ...

  6. SLAM中的优化理论(二)- 非线性最小二乘

    本篇博客为系列博客第二篇,主要介绍非线性最小二乘相关内容,线性最小二乘介绍请参见SLAM中的优化理论(一)-- 线性最小二乘.本篇博客期望通过下降法和信任区域法引出高斯牛顿和LM两种常用的非线性优化方 ...

  7. matrix()方法与translate()、scale()、rotate()、skew()方法的关系

    2D变换方法translate().scale().rotate().skew()与matrix()的关系举例介绍. 一.介绍 2D变换方法: translate():根据左(X轴)和顶部(Y轴)位置 ...

  8. juquery 中 size()和length的区别 以及优缺点

    size()是jQuery提供的函数,而length是属性(不带括号).jQuery提供的源代码是这样的:size: function() {return this.length;}其实也就是说,在j ...

  9. CRM权限管理

    CRM权限管理 一.概念 权限管理就是管理用户对于资源的操作.本 CRM 系统的权限(也称作资源)是基于角色操作权限来实现的,即RBAC(Role-Based Access Control,基于角色的 ...

  10. .net操作IIS,新建网站,新建应用程序池,设置应用程序池版本,设置网站和应用程序池的关联

    ServerManager类用来操作IIS,提供了很多操作IIS的API.使用ServerManager必须引用Microsoft.Web.Administration.dll,具体路径为:%wind ...