python入门第十四天__装饰器

作用域: L E G B

高阶函数

 既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

闭包

如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)、 这是一种现象。

闭包=函数块+定义函数时的环境

闭包=内部函数块+定义函数时的环境

def outer():
    x=10
    def inner():   #条件1、内部函数
        print(x)   #条件2、对于inner而言,x就是外部函数的变量
    return inner    #结论:内部函数inner就是一个闭包

# print(outer().__name__)
# print(outer()())

# outer()()
#inner() 1、不能调用inner() 局部函数,相当于局部变量  全局无法调用

f=outer()
#f()      2、为什么当外部函数结束执行后,还可以调用x

装饰器

由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。

>>> def now():
...     print('2015-3-25')
...
>>> f = now
>>> f()
2015-3-25

函数对象有一个__name__属性,可以拿到函数的名字:

>>> now.__name__
'now'
>>> f.__name__
'now'

现在,假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。

本质上,decorator就是一个返回函数的高阶函数。所以,我们要定义一个能打印日志的decorator,可以定义如下:

def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

观察上面的log,因为它是一个decorator,所以接受一个函数作为参数,并返回一个函数。我们要借助Python的@语法,把decorator置于函数的定义处:

@log
def now():
    print('2015-3-25')

 调用now()函数,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志:

>>> now()
call now():
2015-3-25

@log放到now()函数的定义处,相当于执行了语句: now = log(now) 

由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。

wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。

装饰器学习:

需求:编写一个可以运行的程序

import time

def foo():

    print('foo.....')
    time.sleep(2)

foo()

需求:添加一个功能,计算程序运行花费时间

import time

def foo():
    start=time.time()
    print('foo.....')
    time.sleep(2)
    end=time.time()
    print('时间花费%s'%(end-start))

foo()

结果:弊端:修改了原来函数的代码。

foo.....
时间花费2.0136001110076904

需求:如果需要对多个程序,添加一个功能,计算程序运行花费时间

 1 '''
 2 Created on 2018年6月26日
 3 
 4 @author: Administrator
 5 '''
 6 import time
 7 
 8 def bar():
 9     print('bar.....')
10     time.sleep(3)
11     
12 def foo():
13     print('foo...')
14     time.sleep(2)
15     
16 def show_time(f):
17     start=time.time()
18     f()    
19     end=time.time()    
20     print('时间花费%s'%(end-start))    
21 
22 
23 show_time(foo)
24 show_time(bar)

结果:   弊端:修改了调用方式。。。。 原来是 foo() ,现在是 show_time(foo)  

foo...
时间花费2.006999969482422
bar.....
时间花费3.0136003494262695

需求:如果需要对多个程序,添加一个功能,计算程序运行花费时间。调用方式不能改变 foo() 

'''
Created on 2018年6月26日

@author: Administrator
'''
import time

def bar():
    print('bar.....')
    time.sleep(3)
    
def foo():
    print('foo...')
    time.sleep(2)
    
def show_time(f):
    def inner():
        start=time.time()
        f()    
        end=time.time()    
        print('时间花费%s'%(end-start))
    return inner
    
# def show_time(f):
#     start=time.time()
#     f()    
#     end=time.time()    
#     print('时间花费%s'%(end-start))    

foo=show_time(foo)
foo() #计算程序运行时间


bar() #不需要计算程序运行时间,直接调用

结果:

foo...
时间花费2.0146002769470215
bar.....

上面一个例子就是python的装饰器的使用方法。同时python还提供一个更加美观的装饰器调用方法:

 1 '''
 2 Created on 2018年6月26日
 3 
 4 @author: Administrator
 5 '''
 6 import time
 7 
 8 def show_time(f):
 9     def inner():
10         start=time.time()
11         f()    
12         end=time.time()    
13         print('时间花费%s'%(end-start))
14     return inner
15 '''    
16 ------------------------------------------------------------   
17 def foo():
18     print('foo...')
19     time.sleep(2)
20 
21 foo=show_time(foo)
22 
23 foo()
24 ---------------------等同于下面的方法-------------------------------
25 '''
26 @show_time   #完全等价    foo=show_time(foo)
27 def foo():
28     print('foo...')
29     time.sleep(2)
30 @show_time   #完全等价    bar=show_time(bar)   
31 def bar():
32     print('bar.....')
33     time.sleep(3)
34     
35 foo()
36 bar()
'''
Created on 2018年6月26日

@author: Administrator
'''
import time

def show_time(f):
    def inner():
        start=time.time()
        f()    
        end=time.time()    
        print('时间花费%s'%(end-start))
        return f
    return inner

@show_time   #完全等价    foo=show_time(foo)
def foo():
    print('foo...')
    time.sleep(2)
@show_time   #完全等价    bar=show_time(bar)   
def bar():
    print('bar.....')
    time.sleep(3)
    
foo()
bar()

结果:

foo...
时间花费2.0
bar.....
时间花费3.0

练习:请设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间:

 1 '''
 2 Created on 2018年6月26日
 3 
 4 @author: Administrator
 5 '''
 6 # -*- coding: utf-8 -*-
 7 import time
 8 def metric(fn):
 9     def inner(*args):
10         start=time.time()
11         
12         print(fn(*args))
13         end=time.time()    
14         print('程序名%s,时间花费%s'%(fn.__name__,end-start))
15         return fn(*args)
16     return inner
17 
18 # 测试
19 @metric #完全等价    fast=metric(fast)
20 def fast(x, y):
21     time.sleep(1)
22     return x + y;
23 
24 @metric
25 def slow(x, y, z):
26     time.sleep(2)
27     return x * y * z;
28 
29 f = fast(11, 22)
30 s = slow(11, 22, 33)
31 if f != 33:
32     print('测试失败!')
33 elif s != 7986:
34     print('测试失败!')

结果:

33
程序名fast,时间花费1.0
7986
程序名slow,时间花费2.0

猜你喜欢

转载自www.cnblogs.com/Mengchangxin/p/9229178.html