Python装饰器

python装饰器

首先要明白的一点是,装饰器装饰的是函数。python之中为什么会有这样的需求?

需求是怎么来的

def foo():
    print 'in foo()'

foo()

这是一个函数,如果需要对这个函数增加一些功能,比如需要计算这个函数运行所消耗的时间。

import time
def foo():
    start = time.clock()
    print 'in foo()'
    end = time.clock()
    print 'used:', end - start

foo()

如果其他函数也需要计算运行时间呢?复制代码?DRY,所以可以将计算函数运行时间的功能抽象出来。

import time

def foo():
    print 'in foo()'

def timeit(func):
    start = time.clock()
    func()
    end =time.clock()
    print 'used:', end - start

timeit(foo)

嗯,看上去挺不错的。不过这里的弱点是修改了调用部分的代码,关键是有的时候如果调用的函数是库函数的话就麻烦了。

所以这个时候想到的就是对foo进行包装,将timeit编写为对foo的包装函数,传入foo之后对foo进行加强,返回一个新的foo。

#-*- coding: UTF-8 -*-
import time

def foo():
    print 'in foo()'

# 定义一个计时器,传入一个函数,并返回另一个附加了计时功能的函数
def timeit(func):
    # 定义一个内嵌的包装函数,给传入的函数加上计时功能的包装
    def wrapper():
        start = time.clock()
        func()
        end =time.clock()
        print 'used:', end - start
    # 将包装后的函数返回
    return wrapper

foo = timeit(foo)
foo()

PS:在在这个例子中,函数进入和退出时需要计时,这被称为一个横切面(Aspect),这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。与传统编程习惯的从上往下执行方式相比较而言,像是在函数执行的流程中横向地插入了一段逻辑。在特定的业务领域里,能减少大量重复代码。

问题:如果foo带参数怎么办?
很简单,装饰器之中的包装函数的参数和被装饰的函数的参数需要统一。

def deco(func):
    def _deco(a, b):
        print("before myfunc() called.")
        ret = func(a, b)
        print("  after myfunc() called. result: %s" % ret)
        return ret
    return _deco

@deco
def myfunc(a, b):
    print(" myfunc(%s,%s) called." % (a, b))
    return a + b

再举一个例子是Django之中的Signal装饰器:

def receiver(signal, **kwargs):
    def _decorator(func):
        if isinstance(signal, (list, tuple)):
            for s in signal:
                s.connect(func, **kwargs)
        else:
            signal.connect(func, **kwargs)
        return func
    return _decorator

语法糖

Python对装饰器提供了语法糖:

import time

def timeit(func):
    def wrapper():
        start = time.clock()
        func()
        end =time.clock()
        print 'used:', end - start
    return wrapper

@timeit
def foo():
    print 'in foo()'

foo()

内置装饰器

内置的装饰器有三个,分别是staticmethod、classmethod和property。作用分别是把类中定义的实例方法变成静态方法、类方法和类属性。

class Rabbit(object):

    def __init__(self, name):
        self._name = name

    @staticmethod
    def newRabbit(name):
        return Rabbit(name)

    @classmethod
    def newRabbit2(cls):
        return Rabbit('')

    @property
    def name(self):
        return self._name

示例比较简单,其中的函数是可以进行扩展的。这里@property定义的是一个只读属性,如果需要可写,则需要再一定一个setter:

@name.setter
def name(self,name):
    self._name = name
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值