python: 设计模式(design pattern)之修饰器模式(decorator)

修饰器模式是面向对象编程领域的一种设计模式。 通过向一个类对象动态的添加新的行为而实现。 修饰器可以给某个对象添加一些功能, 而不是整个类添加功能, 所以很灵活。 

在python中, 我们可以使用decorators对callable的objects(注意包括functions, methods, 或者类classes)进行一些简单的修饰, 使得这些objects具有一些新的行为。

要理解decorators, 我们必须首先知道, python中, functions也是一个对象, 就想string, variables, class , integers等一样。 函数是根据给定的参数吐出产生的值的。

我们可以将一个函数作为一个参数传递给另一个函数, 也可以将一个函数赋值给一个变量, 或者函数返回一个函数。 

如下, 返回一个函数:

def foobar(original_function):
 
    # make a new function
    def new_function():
        # some code
 
    return new_function

decorator的定义:

一个decorator就是一个function, 吃callable object作为其参数, 然后将添加修饰后的callable obeject(例如函数)作为一个value返回去。

如下例就是对类进行修饰。例如, 下面就是一个修饰器:

def verbose(original_function):
 
    # make a new function that prints a message when original_function starts and finishes
    def new_function(*args, **kwargs):
        print("Entering", original_function.__name__)
        original_function(*args, **kwargs)
        print("Exiting ", original_function.__name__)
 
    return new_function

要使用decorator也很简单。 

我们可以将一个函数传进去, 得到新一个新的修饰后的函数talkative_widget_func。 如下:

def widget_func():
    # some code
 
talkative_widget_func = verbose(widget_func)

另外, 注意, 我们不光可以使用一个新的修饰后的函数去替换掉原有的函数, 我们还可以去得到一个增强版的原始的函数, 注意, 这不是新的函数, 而是在原来函数的基础上加上了一层封装, 如下:

def widget_func():
    # some code
 
widget_func = verbose(widget_func)

注意上述返回的函数命名为widget_func, 和传进去的原始函数一样。

除此之外, python还有一个decortation syntax。 也就是使用“@”去创建decoration lines. 这个feature就是语法糖(syntax sugar), 是的我们可以将上面的例子重新写为如下形式:

@verbose
def widget_func():
    # some code

上述产生的结果和上面的增强版本一样了。 这样我们的新的widget_func函数就具有原始的widget_func所有的行为在加上varbose修饰器添加的行为了。

不光可以修饰函数, 也可以对类进行修饰。程序如下:

#!/usr/bin/python

#decotor design pattern

import sys

YELLOW = '\033[93m'
RED = '\033[91m'
NORMAL = '\033[0m'

class Person(object):
    def __init__(self, name, age): # constructor
        self.name = name
        self.age = age
    
    def __str__(self):
        return '%s is %s' %(self.name, self.age)
# decorator class to wrapps an object passed in
#for age < 20, print NOEMAL
#for 20 < age < 20, print YELLOW
#for age > 30, print RED
class PersonDecorator(Person):
    def __init__(self, person):
        self._person = person
        
    def __getattr__(self, name):
        return getattr(self._person, name)
        
    def __str__(self):
        age = self._person.age
        colour = NORMAL
        if age >= 30:
            colour = RED
        elif age >= 20:
            colour = YELLOW
        
        return '%s%s%s' %(colour, self._person.__str__(), NORMAL)

def main():
    p = [] # list of person
    p.append(Person('Micheal', 25))
    p.append(Person('Kate', 2))
    p.append(Person('Mark', 48))
    p.append(Person('Matt', 21))
    
    for person in p:
        if '-c' in sys.argv:
            person = PersonDecorator(person)
        print person
        
if __name__ == '__main__':
    main()

运行结果如下:

《python: 设计模式(design pattern)之修饰器模式(decorator)》

附录: 解释(stackoverflow摘录)

*args and **kwargs

语法* 和 **默认使用的。 基本上学习python的时候用不上。 当你不确定函数中应该传进去几个参数的时候,可以使用它。 即it allows you to pass an arbitary number of arguments to your function: 如下:
《python: 设计模式(design pattern)之修饰器模式(decorator)》

Similarly, **kwargs allows you to handle named arguments that you have not defined in advance:

如下:

>>> def table_things(**kwargs): ... for name, value in kwargs.items(): ... print '{0} = {1}'.format(name, value) ... >>> table_things(apple = 'fruit', cabbage = 'vegetable') cabbage = vegetable apple = fruit

You can also use both in the same function definition but 
*args
 must occur before 
**kwargs
.

http://www.wklken.me/posts/2013/12/21/how-to-use-args-and-kwargs-in-python.html

解释如下:在函数中使用*和**是用于传递可变长参数, *args用于传递非命名剪枝可变长参数列表。 **kwargs用作传递键值可变长参数列表。 如下, 传递一个位置参数和两个可变长参数。

def test_var_args(farg, *args):
    print "formal arg:", farg
    for arg in args:
        print "another arg:", arg

test_var_args(1, "two", 3)


《python: 设计模式(design pattern)之修饰器模式(decorator)》


def test_var_kwargs(farg, **kwargs):
    print "formal arg:", farg
    for key in kwargs:
        print "another keyword arg: %s: %s" % (key, kwargs[key])

test_var_kwargs(farg=1, myarg2="two", myarg3=3)

运行结果如下:

《python: 设计模式(design pattern)之修饰器模式(decorator)》

上述语法也可以出现在调用函数中, 如下:

def test_var_args_call(arg1, arg2, arg3):
    print "arg1:", arg1
    print "arg2:", arg2
    print "arg3:", arg3

args = ("two", 3)
test_var_args_call(1, *args)

如下:

《python: 设计模式(design pattern)之修饰器模式(decorator)》
或者:

def test_var_args_call(arg1, arg2, arg3):
    print "arg1:", arg1
    print "arg2:", arg2
    print "arg3:", arg3

kwargs = {"arg3": 3, "arg2": "two"} #ie dictionary
test_var_args_call(1, **kwargs)

《python: 设计模式(design pattern)之修饰器模式(decorator)》

    原文作者:JUAN425
    原文地址: https://blog.csdn.net/a130737/article/details/45013467
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞