Python装饰器心得笔记(2)

def debug(level):
    def wrapper(func):
        def inner_wrapper(*args, **kwargs):
            print '[{level}]: enter {func}()'.format(level=level,func=func.__name__)
            return func(*args, **kwargs)
        return inner_wrapper
    return wrapper

@debug(level='Debug')
def func_enter(something):
    print "enter {}!".format(something)

@debug(level='Debug')
def func_quit(something):
    print "enter {}!".format(something)  # bug here


if __name__ == '__main__':
    func_enter("enter_func")
    func_quit("quit_func")

运行结果:

[Debug]: enter func_enter()
enter enter_func!
[Debug]: enter func_quit()
enter quit_func!
(wda_python) bash-3.2$

基于类实现的装饰器

装饰器函数其实是这样一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。在Python中一般callable对象都是函数,但也有例外。只要某个对象重载了__call__()方法,那么这个对象就是callable的。

class Test():
    def __call__(self, *args, **kwargs):
        print 'call me!'

t = Test()
t()

运行结果:

call me!
(wda_python) bash-3.2$

像__call__这样前后都带下划线的方法在Python中被称为内置方法,有时候也被称为魔法方法。重载这些魔法方法一般会改变对象的内部行为。上面这个例子就让一个类对象拥有了被调用的行为。

回到装饰器上的概念上来,装饰器要求接受一个callable对象,并返回一个callable对象(不太严谨,详见后文)。那么用类来实现也是也可以的。我们可以让类的构造函数__init__()接受一个函数,然后重载__call__()并返回一个函数,也可以达到装饰器函数的效果。

class Debug_info(object):
    def __init__(self, func):
        self.func = func

def __call__(self, *args, **kwargs):
        print "[DEBUG]: enter function {func}()".format(func=self.func.__name__)
        return self.func(*args, **kwargs)

@Debug_info
def func_enter(something):
    print 'enter {}!'.format(something)

if __name__ == '__main__':
    func_enter("enter_func")

运行结果:

[DEBUG]: enter function func_enter()
enter enter_func!
(wda_python) bash-3.2$

带参数的类装饰器

如果需要通过类形式实现带参数的装饰器,那么会比前面的例子稍微复杂一点。那么在构造函数里接受的就不是一个函数,而是传入的参数。通过类把这些参数保存起来。然后在重载__call__方法是就需要接受一个函数并返回一个函数。

#coding: utf-8

class Debug_info(object):
    def __init__(self, level='INFO'):
        self.level= level

def __call__(self, func):  # 接受函数
        def wrapper(*args, **kwargs):
            print "[{level}]: enter function {func}()".format(level=self.level,func=func.__name__)
            func(*args, **kwargs)
        return wrapper

@Debug_info(level='INFO')
def func_enter(something):
    print 'enter {}!'.format(something)

if __name__ == '__main__':
    func_enter("enter_func")

运行结果:

[INFO]: enter function func_enter()
enter enter_func!
(wda_python) bash-3.2$

内置的装饰器

在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改:

s = Student()
s.score = 9999

这显然不合逻辑。为了限制score的范围,可以通过一个set_score()方法来设置成绩,再通过一个get_score()来获取成绩,这样,在set_score()方法里,就可以检查参数:

class Student(object):

def get_score(self):
        return self._score

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/5464465069624e34263f951661ba85a2.html