一步一步解释Python装饰器

装饰器,英文名Decorator,有一个“@”符号。如果学过Java,就知道它和注解(Annotation)类似。

Python的实现是通过语法糖,本文旨在解开语法糖,用代码回答问题。

先来看一个装饰器的例子:

def deco(func):
    print("before deco.")
    func()
    print("after deco.")
    return func

@deco
def myfunc():
    print("myfunc called.")

myfunc()
myfunc()

那么执行结果是:

before deco.
myfunc called.
after deco.
myfunc called.
myfunc called.

先不要问为什么?再来看下面的例子:

def deco(func):
    print("before deco.")
    func()
    print("after deco.")
    return func

def myfunc():
    print("myfunc called.")

myfunc = deco(myfunc)
myfunc()
myfunc()

执行结果是:

before deco.
myfunc called.
after deco.
myfunc called.
myfunc called.

有没有看到,执行结果是一样的,就是这样,@deco的作用相当于是 myfunc = deco(myfunc) 这一句赋值语句,为什么说它是语法糖,就是这样啊!

在Python这里一切都是那样自然而然,你可以用原生的代码来解释装饰器。

上面的例子只是做介绍用,目的是通过不使用装饰器的代码来说明。

下面举一个常用的例子,记录一个函数运行的时间:

import time
import platform
def time_cost(func):
    def _time_cost():
        if platform.system() == 'Windows':
            beg = time.clock()
            func()
            print('cost:', (time.clock() - beg))
        else:
            beg = time.time()
            func(num)
            print('cost:', (time.time() - beg))           
    return _time_cost

@time_cost
def calc_sleep():
    for item in range(3):
        time.sleep(1)
    print('calc_sleep()')

calc_sleep()

执行结果:

calc_sleep()
cost: 3.00739021746

可以想到如果不用装饰器那么就是这样的:

import time
import platform
def time_cost(func):
    def _time_cost():
        if platform.system() == 'Windows':
            beg = time.clock()
            func()
            print('cost:', (time.clock() - beg))
        else:
            beg = time.time()
            func(num)
            print('cost:', (time.time() - beg))           
    return _time_cost

def calc_sleep():
    for item in range(3):
        time.sleep(1)
    print('calc_sleep()')

calc_sleep = time_cost(calc_sleep)
calc_sleep()

执行结果:

calc_sleep()
cost: 3.00060552257

那么有的时候又想记录花费时间,又想取得执行所在目录怎么办?

import time
import platform
import os
def time_cost(func):
    def _time_cost():
        if platform.system() == 'Windows':
            beg = time.clock()
            func()
            print('cost:', (time.clock() - beg))
        else:
            beg = time.time()
            func(num)
            print('cost:', (time.time() - beg))           
    return _time_cost

def curr_dir(func):
    def _curr_dir():
        print(os.getcwd())
        func()
    return _curr_dir
        
@time_cost
@curr_dir  
def calc_sleep():
    for item in range(3):
        time.sleep(1)
    print('calc_sleep()')

calc_sleep()

执行结果:

C:\Program Files (x86)\Notepad++
calc_sleep()
cost: 3.00123433447

那么多个装饰器,不用@符号会是怎么样的呢?

import time
import platform
import os
def time_cost(func):
    def _time_cost():
        if platform.system() == 'Windows':
            beg = time.clock()
            func()
            print('cost:', (time.clock() - beg))
        else:
            beg = time.time()
            func(num)
            print('cost:', (time.time() - beg))           
    return _time_cost

def curr_dir(func):
    def _curr_dir():
        print(os.getcwd())
        func()
    return _curr_dir
        
 
def calc_sleep():
    for item in range(3):
        time.sleep(1)
    print('calc_sleep()')

calc_sleep = time_cost(curr_dir(calc_sleep))
calc_sleep()

执行结果:

C:\Program Files (x86)\Notepad++
calc_sleep()
cost: 3.0009753887



你可能感兴趣的:(Python装饰器)