python高级编程(四)--闭包、装饰器

来源:互联网 发布:初三物理视频教程软件 编辑:程序博客网 时间:2024/06/13 01:50

1. 闭包

  • 说明:在一个函数中又定义了一个函数,并且内部函数可以引用外部函数的参数和局部变量,当外部函数返回内部函数时,相关参数和变量都保存在返回的函数中,这种称为闭包。

一个闭包的实际例子:

"""闭包的例子"""def line_conf(a,b):    def line(x):        return a*x + b    return lineline1 = 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@w1def 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>"@makeBolddef test1():    return "hello world-1"@makeItalicdef test2():    return "hello world-2"@makeBold@makeItalicdef test3():    return "hello world-3"print(test1())print(test2())print(test3())
  • 装饰器–无参数的函数:
"""无参数的函数"""from time import ctime,sleepdef 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@timefundef 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 timedef f(func):    def wrapped_func(a,b)        print(a,b)        func(a,b)    return wrapped_func@fdef test(a,b):    print(a+b)test(3,5)time.sleep(2)test(2,4)

运行结果:
3,5
8
2,4
6

  • 装饰器函数-不定长参数
import timedef f(func):    def wrapped_func(*args, **kwargs):        fun(*args,**kwargs)    return wrappend_func@fdef 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@fdef test():    print("I am test")@fdef 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 timedef 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()@Testdef 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之前的函数体。

阅读全文
0 0
原创粉丝点击