作用域: 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