1. 闭包
- 说明:在一个函数中又定义了一个函数,并且内部函数可以引用外部函数的参数和局部变量,当外部函数返回内部函数时,相关参数和变量都保存在返回的函数中,这种称为闭包。
一个闭包的实际例子:
"""闭包的例子"""
def line_conf(a,b):
def line(x):
return a*x + b
return line
line1 = line_conf(1,1)
line2 = line_conf(4,5)
print(line1(5))
print(line2(5))
结果:
6
25
- 闭包的优缺点:
优点:(1)闭包具有提高代码可复用性的作用(2)减少了代码的可移植性。
缺点:由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存。
2. 装饰器
假设我们需要增强一个函数的功能,但又不希望修改函数的定义,在代码运行期间动态增加的方式,称为装饰器(Decorator)
- 装饰器的作用:
- 引入日志
- 函数执行时间统计
- 执行函数前预备处理
- 执行函数后清理功能
- 权限校验等场景
- 缓存
一个装饰器的例子:
def w1(func):
def inner():
print("----权限验证----")
func()
return inner
@w1
def f1():
print("----f1----")
运行结果:
—-权限验证—-
—-f1—-
整个运行过程如下:
(1). def w1(func):—–> 将w1函数加载到内存
(2). @w1
: —-> 执行w1函数,并将@W1
下面的函数作为w1函数的参数,即@w1
等价于w1(f1)inner()函数,将执行完的W1函数返回值赋值给@w1
下面的函数的函数名f1即将w1的返回值再重新赋值给f1.
- 一个装饰器或多个装饰器使用:
# 定义函数:完成包裹数据
def makeBold(func):
def wrapped():
return "<b>" + func() + "</b>"
return wrapped
# 定义函数:完成包裹数据
def makeItalic(func):
def wrapped():
return "<i>" +func() + "</i>"
@makeBold
def test1():
return "hello world-1"
@makeItalic
def test2():
return "hello world-2"
@makeBold
@makeItalic
def test3():
return "hello world-3"
print(test1())
print(test2())
print(test3())
- 装饰器–无参数的函数:
"""无参数的函数"""
from time import ctime,sleep
def timefun(func):
def wrapped_func():
print("---%s called at %s" %(func.__name__,ctime()))
func()
return wrapped_func
# foo = timefun(foo)
# foo 先作为参数赋值给func后,foo接收指向timefun返回的wrapped_func
@timefun
def foo():
print("我是无参数函数")
foo()
sleep(2)
foo()
# 调用foo(),即等价调用wrapped_func()
# 内部函数wrapped_func被引用,所以外部函数的func变量(自由变量)并没有释放
# func里保存的是原foo函数对象
运行结果:
— foo called at Sun Aug 13 17:12:21 2017
我是无参函数
— foo called at Sun Aug 13 17:12:21 2017
我是无参函数
- 装饰器–有参数函数
import time
def f(func):
def wrapped_func(a,b)
print(a,b)
func(a,b)
return wrapped_func
@f
def test(a,b):
print(a+b)
test(3,5)
time.sleep(2)
test(2,4)
运行结果:
3,5
8
2,4
6
- 装饰器函数-不定长参数
import time
def f(func):
def wrapped_func(*args, **kwargs):
fun(*args,**kwargs)
return wrappend_func
@f
def test1(a,b,c):
print(a+b+c)
test(3,5,7)
time.sleep(2)
test(2,4,9)
- 装饰器–有return
import time
def f(func):
def wrapped_f():
print("====%s called ====="%func.__name__)
f()
return wrapped_f
@f
def test():
print("I am test")
@f
def getInfo():
return "---hello---"
test()
time.sleep(2)
test()
print(getInfo())
执行结果:
====test called =====
I am test
====test called =====
I am test
====getInfo called =====
None
如果装饰器为 return func() 运行结果:
====test called =====
I am test
====test called =====
I am test
====getInfo called =====
—hello—
- 装饰器–带参数,在原有装饰器的基础上,设置外部变量
import time
def f_arg(pre="hello"):
def f(func):
def wrapped_f():
print("===%s call ==="%func.__name__)
return func
return wrapped_func
return f
@f_arg("java")
def test1():
print("I am test1")
@f-arg("python")
def test2():
print("I am test2")
test1()
time.sleep(2)
test1()
test2()
time.sleep(2)
test2()
运行结果:
====test1 called ===
====test1 called ===
====test2 called ===
====test2 called ===
====>>>>>>> 可以理解为 test() = f_arg(“java”)(test)()
装饰过程:
(1).调用f_arg(“hello”)
(2).将步骤1得到的返回值,即f返回,然后f()
(3).将f(test1)的结果返回,即wrapped_f
(4).让test1 = wrapped_f , 即test1现在指向wrapped_f
- 装饰器–类装饰器
"""类装饰器"""
class Test(object):
def __init__(self,func):
print("==>>>初始化")
print("==>>>func name is %s"%func.__name__)
self.__func = func
def __call__(self):
print("====装饰器中的功能====")
self.__func()
@Test
def test():
print("====test====")
test()
运行结果:
==>>>初始化
==>>>func name is test
====装饰器的功能====
====test====
说明:
(1). 当用Test来装作装饰器对test函数进行装饰的时候,首先会创建Test的实例对象。并且会把test这个函数名当做参数传递到__init__
方法中。即在__init__
方法中的属性self.__func
指向了test指向的函数。
(2). test指向了用Test创建出来的实例对象
(3). 当在使用test()进行调用时,就相当于让这个对象(),因此会调用这个对象的__call__
方法
(4). 为了能够在__call__
方法中调用原来test指向的函数体,所以在__init__
方法中就需要一个实例属性来保存这个函数体的引用
所以才有了self.__func
= func这句代码,从而在调用__call__
方法中能够调用到test之前的函数体。