面向对象学习笔记6----装饰器

本文详细解析了Python中的闭包概念,探讨了如何使用闭包来创建装饰器,进一步介绍了装饰器的工作原理及其实现方式。通过具体实例,展示了如何利用装饰器为函数添加额外功能,如计算函数执行时间,以及如何处理带参数的函数装饰。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

闭包

➢如果一个函数定义在另一个函数的作用域内,并且引用了外层函数的变量,则该函数称为闭包。
闭包是Python所支持的一种特性,它让在非global scope定义的函数可以引用其外围空间中的变量,这些外围空间中被引用的变量叫做这个函数的环境变量。环境变量和这个非全局函数一起构成了闭包。
闭包-------返回一个函数以及执行这个函数所需要的相关变量。一般用在嵌套函数中。

#coding=utf-8
def outer() :
    name = "python"
    def inner() :
        print (name)
    return inner

res = outer()
res()
print (res. __closure__)

在这里插入图片描述

#coding=utf-8
def outer(name) :
    def inner() :
        print (name)
    return inner

res1 = outer("python")
print (res1. __closure__)
res2 = outer("java")
res1()
res2()

在这里插入图片描述

装饰器-------给函数增加一些通用的功能

比如给所有的函数都计算一下执行的时间。
装饰器其实就是一个闭包,把一个函数当做参数后返回一个替代版函数。
在代码运行期间在不改变原函数定义的基础上,动态给该函数增加功能的方式,称之为装饰器(Decorator)。
装饰器是一个很著名的设计模式,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
总体来说,装饰器其实也是一个函数,一个用来包装函数的函数,返回一个修改之后的函数对象,将其重新赋值给原来的标识符,并永久丧失对原始函数对象的访问。
1、函数调用基础知识复习:

>>> def func():
...     print("hi")
...     return 10
...
>>> func()
hi
10
>>> a=func()
hi
>>> a
10
>>> a=func  #把函数对象赋给a
>>> a
<function func at 0x002B5B70>
>>> a()  #调用函数
hi
10

2、装饰器的实现原理

def deco(func):
    def _deco():
        print ("before myfunc() called.")
        func()
        func()
        print (" after myfunc() called.")
        # 不需要返回func,实际上应返回原函数的返回值
    return _deco

def myfunc(): #等价于闭包:_deco()+myfunc
    print (" myfunc() called.")
    return 'ok'

myfunc=deco(myfunc)
myfunc()  #等价于闭包:_deco()+myfunc

在这里插入图片描述
3、最简单的装饰器实现

def deco(func):
    def _deco():
        print ("before myfunc() called.")
        func()
        print (" after myfunc() called.")
        # 不需要返回func,实际上应返回原函数的返回值
    return _deco
    
#@deco等价于myfunc = deco(myfunc)
@deco
def myfunc():
    print (" myfunc() called.")
    return 'ok'

myfunc()
myfunc()

在这里插入图片描述
装饰器的好处:能够给所有的函数增加一些附加的功能。
本质就是:@deco是个装饰函数,他需要返回一个闭包。闭包有_deco函数对象+原函数对象(闭包变量)。
_deco函数对象本质:执行了附加的功能,并且执行了原函数。
小练习:利用装饰器给函数执行计算下耗时

import time
def deco(func):
    def _deco():
        print ("before myfunc() called.")
        time1=time.time()
        func()
        time.sleep(2)
        time2=time.time()
        print (" after myfunc() called.")
        print("%s函数执行耗时:%s" %(func.__name__,time2-time1))
        # 不需要返回func,实际上应返回原函数的返回值
    return _deco

@deco
def myfunc(): #等价于闭包:_deco()+myfunc
    print (" myfunc() called.")
    return 'ok'

myfunc()  #等价于闭包:_deco()+myfunc

在这里插入图片描述
myfunc和myfunc()执行的结果区分:

#coding=utf-8
def deco(func):
    print("hi")
    def _deco():
        print ("before myfunc() called.")
        func()
        print (" after myfunc() called.")
        # 不需要返回func,实际上应返回原函数的返回值
    return _deco

@deco
def myfunc(): #等价于闭包:_deco()+myfunc
    print (" myfunc() called:")

#myfunc #--->deco(myfunc)--->执行结果:返回闭包_deco+myfunc
myfunc()  #--->deco(myfunc)--->执行结果:返回闭包_deco+myfunc
          #加了括号后--->_deco()被执行了

在这里插入图片描述

4、对带参数的函数进行装饰:

import time
def deco(func):
    def _deco(a,b):
        print ("before myfunc() called.")
        time1=time.time()
        func(a,b)
        time.sleep(2)
        time2=time.time()
        print (" after myfunc() called.")
        print("%s函数执行耗时:%s" %(func.__name__,time2-time1))
        # 不需要返回func,实际上应返回原函数的返回值
    return _deco

@deco
def myfunc(a,b): #等价于闭包:_deco(a,b)+myfunc
    print (" myfunc() called:",a,b)
    return 'ok'

myfunc(1,2)  #等价于闭包:_deco(1,2)+myfunc

在这里插入图片描述
5、对参数数量不确定的函数进行装饰----兼容可变参数:

#coding=utf-8
def deco(func):
    print("hi")
    def _deco(*arg,**kw):
        print ("before myfunc() called.")
        func(*arg,**kw)
        print (" after myfunc() called.")
        # 不需要返回func,实际上应返回原函数的返回值
    return _deco

@deco
def myfunc(a,b): #等价于闭包:_deco(a,b)+myfunc
    print (" myfunc() called:",a,b)

@deco
def myfunc1(a,b,c,d,*agg,**kw): #等价于闭包:_deco(a,b,c,d,*agg,**kw)+myfunc
    print (" myfunc() called:",a,b,c,d)
    print(kw)

#myfunc #--->deco(myfunc)--->执行结果:返回闭包_deco+myfunc
myfunc(1,2)  #--->deco(myfunc)--->执行结果:返回闭包_deco+myfunc
          #加了括号后--->_deco()被执行了
myfunc1(1,2,3,4,e=10)

在这里插入图片描述
6、让装饰器带参数,多了一层闭包

#coding=utf-8
def deco(arg):
    print("1")
    def _deco(func):
        print("2")
        def __deco():
            print("3")
            print ("before %s called [%s]." % (func.__name__, arg))
            func()
            print (" after %s called [%s]." % (func.__name__, arg))
        return __deco
    return _deco

@deco("mymodule")  #等价于deco("mymodule")--->一级闭包_deco+arg
#二级闭包_deco(myfunc)+arg
#myfunc()--->_deco()
def myfunc():
    print (" myfunc() called.")

#myfunc #执行1和2,没有执行3--->返回闭包_deco+arg+myfunc
myfunc() #执行1和2,3--->_deco()

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值