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

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. 第2章 rsync(二):inotify+rsync详细说明和sersync

    本文目录: inotify+rsync 1.1 安装inotify-tools 1.2 inotifywait命令以及事件分析 1.3 inotify应该装在哪里 1.4 inotify+rsync示 ...

  2. Angular4.0学习笔记 从入门到实战打造在线竞拍网站学习笔记之二--路由

    Angular4.0基础知识见上一篇博客 路由 简介 接下来学习路由的相关知识 本来是不准备写下去的,因为当时看视频学的时候感觉自己掌握的不错 ( 这是一个灰常不好的想法 ) ,过了一段时间才发现An ...

  3. JAVA异常处理之finally中最好不要使用return

    finally 语句块中, 最好不要使用return, 否则会造成已下后果; 1, 如果catch块中捕获了异常, 并且在catch块中将该异常throw给上级调用者进行处理, 但finally中re ...

  4. java中方法调用

    JAVA中方法的调用[基础] 一.调用本类中的方法 方法一.被调用方法声明为static ,可以在其他方法中直接调用.示例代码如下: public class HelloWord { /** * @p ...

  5. git中常用的指令

    1.初始化仓库 git init2.设置用户名与邮箱 git config --global user.name 'name' git config --global user.email 'emai ...

  6. spring Bean类自动装载实现

    先贴spring的开发文档,有助于大家学习http://shouce.jb51.net/spring/beans.html#beans-factory-class 一直想研究一下spring bean ...

  7. MQ选型对比文档

    几种MQ产品说明:     ZeroMQ :  扩展性好,开发比较灵活,采用C语言实现,实际上他只是一个socket库的重新封装,如果我们做为消息队列使用,需要开发大量的代码    RabbitMQ  ...

  8. Mongodb相关 (Shell命令 / mongoose)

    Mongodb相关 1.创建一个文件夹作为数据库存放的目录 2.打开cmd cd到Mongodb/bin目录去 3.执行mongod --dbpath "第一项创建的文件夹(数据库数据存放目 ...

  9. 使用ExpressionVisitor进行lambadaExpression的动态拼接

    现有如下实体 public class User { public int Id { get; set; } public string Name { get; set; } } 根据这个实体创建一个 ...

  10. 关于flask线程安全的简单研究

    flask是python web开发比较主流的框架之一,也是我在工作中使用的主要开发框架.一直对其是如何保证线程安全的问题比较好奇,所以简单的探究了一番,由于只是简单查看了源码,并未深入细致研究,因此 ...