Python中的装饰器详细解读

简介: Python中的装饰器详细解读


Hello,大家好,我是景天,今天我们来一起聊一聊python中的装饰器。

装饰器 : 主要功能是在不改变原有代码的前提下,为原函数扩展新功能

装饰器(decorator)

定义:装饰器用于拓展原来函数功能的一种语法,返回新函数替换旧函数

优点:在不更改原函数代码的前提下 给函数拓展新的功能

装饰器本质上是一个Python函数(其实就是闭包),它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,

装饰器的返回值也是一个函数对象。装饰器用于有以下场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。

@符号 装饰器的标识符 :

(1) 自动把下面修饰的原函数或者类当成参数传递给装饰器

(2) 把返回的新函数去替换原函数

(1) 装饰器的原型

def kuozhan(_func):
    def newfunc():
        print("吃饭前 ... 饥肠辘辘")
        _func()
        print("吃饭后 ... 肚皮撑撑")
    return newfunc

def func():
    print("我是屌丝...")
    
func = kuozhan(func) # func = newfunc   func() <=> newfunc()
func()

定义装饰器,必须是两层函数,内层函数使用外层函数的形参,外层函数将内层函数返回

没调用闭包函数之前,原函数还是原函数

调用之后,原函数成了扩展函数中的一个参数,并且在内层函数中执行。newfunc是个闭包函数,使用了外层函数的形参

(2) @符号的使用

@符号 装饰器的标识符 :

(1) 自动把下面修饰的原函数当成参数传递给装饰器

(2) 把返回的新函数去替换原函数

def kuozhan(_func):
    def newfunc():
        print("厕所前 ... 干净整齐")
        _func()        
        print("厕所后 ... 臭气熏天")
    return newfunc
    
@kuozhan
def func():
    print("我是高富帅...")

func()

@扩展函数名 把下面函数当参数传递给装饰器,把下面的代码往上传

(3) 装饰器的嵌套

def kuozhan1(_func):
    def newfunc():
        print("厕所前 ... 人模狗样1")
        _func()        
        print("厕所后 ... 牛头马面2")
    return newfunc

def kuozhan2(_func):
    def newfunc():
        print("厕所前 ... 面黄肌瘦3")
        _func()        
        print("厕所后 ... 红光满面4")
    return newfunc


@kuozhan2
@kuozhan1
def func():
    print("我是白富美...5")

func()

@kuozhan2 先把下面@kuozhan1当做参数传递给kuozhan2

@kuozhan1 把func当做参数传递给kuozhan1,然后再把执行结果传递给装饰器kuozhan2

多个装饰器存在时,代码从下往上执行

#给一个函数添加多个装饰器,等价于kuozhan2(kuozhan1(func))

当一个函数具有两个装饰器时的执行顺序

针对装饰器的外层函数,是从下往上执行

(4) 带有参数的装饰器

原函数和新函数的参数和返回值要保持一一对应

def kuozhan(_func):
    def newfunc(who,where,eat):
        print("厕所前 ... 文质彬彬")
        _func(who,where,eat)
        print("厕所后 ... 兽性大发")
    return newfunc

@kuozhan
def func(who,where,eat):
    print("{who}在{where}吃{eat}".format(who=who,where=where,eat=eat)  )
    
func("假率先","浴缸","榴莲") # <=> newfunc()

带有参数的装饰器,即是装饰器的内层函数带有参数,并且带有的参数个数要和原函数的参数个数一样,不一样的话报错

参数个数不一致,报错

(5) 带有参数返回值的装饰器

def kuozhan(_func):
    def newfunc(*args,**kwargs):
        print("手工耿同学向下面拉屎的同学们致敬 ~")
        res = _func(*args,**kwargs)
        print("请使用我的自动便便称重器 ... ")
        return res    #原函数带有返回值,装饰器内层函数也要借助变量将函数执行结果返回
        
    return newfunc
    
@kuozhan
def func(*args,**kwargs):    
    dic = {"liuwenbo":"刘文波","zhanglei":"张磊","songjian":"宋健"}
    lst = []
    try:
        i = 0
        for k,v in kwargs.items():
            # 键在dic中,再去拼凑字符串
            if k in dic:
                # 人名 + 地点 + 拉的重量
                strvar  = dic[k] + "在" + args[i] + "拉了" + v     #调用处地点少了一个,导致args[2]获取不到值,元祖下标越界,所以需要异常处理,抑制异常
                lst.append(strvar)
                i += 1    
    except:
        # print(i) # 2
        # print(list(dic.values())) # ['刘文波', '张磊', '宋健']
        # print(list(dic.values())[i])
        print("{}找不到拉屎的地点而错,请传入他的拉屎地点".format(list(dic.values())[i]))
        
        
    return lst    
    # return ["刘文博在电线杆子下面拉了15吨" , "张磊拉了15斤","宋健拉了15克"]

res = func("电线杆子下面","电影院",liuwenbo="15吨",zhanglei="15斤",songjian="15克")   #这里地点少了一个
print(res)

(6) 使用类装饰器

class Kuozhan():
    def __call__(self,_func):
        return self.kuozhan2(_func)
                
    def kuozhan1(func):
        def newfunc():
            print("厕所前 ... 饥肠辘辘")
            func()
            print("厕所后 ...  酒足饭饱")
        return newfunc
        
    def kuozhan2(self,func):
        def newfunc():
            print("厕所前 ... 蓬头垢面")
            func()
            print("厕所后 ... 衣衫褴褛")
        return newfunc

方式一

@Kuozhan.kuozhan1
def func():
    print("厕所进行时 .... ")

func()


方式二 直接@类名(),通过定义__call__调用来装饰

@Kuozhan()
def func():
    print("厕所进行时 .... ")

func()

过程分析

(7) 带有参数的函数装饰器,用函数将类中的函数装饰一下

def outer(num):

    def kuozhan(_func):
    
        def newfunc1(self):
            print(self)
            print("厕所前 ... 老实巴交")
            _func(self)
            print("厕所后 ... 浑身哆嗦")
            
        def newfunc2(self):
            print(self)
            print("厕所前 ... 狂送人头")
            _func(self)
            print("厕所后 ... 让二追三")
                    
        if num == 1: 
            return newfunc1
        elif num == 2:
            return newfunc2
        elif num == 3:
            return "厕所前,洗洗手,厕所后,簌簌口"
        
    return kuozhan


class MyClass():

    @outer(1)  # (1)@outer(1) => @kuozhan  (2)@kuozhan =>  func1 = newfunc1 => (3) obj.func1() <=> obj.newfunc1(self)
    def func1(self):
        print("向前一小步,文明一大步")
        
    @outer(2)
    def func2(self):
        print("不冲就打包带走")

    @outer(3)
    def func3(self):
        print("请瞄准后发射,尿到外边,说明你短!")

print("<==============>")
obj = MyClass()
obj.func1() # <=> obj.newfunc1()

# print("<==============>")
# obj.func2()
# print("<==============>")
# print(obj.func3)

@outer()来传参,根据不同的参数使用不同的装饰器来对类中的函数来装饰

func3没返回函数,直接返回了属性,直接赋值给变量/打印即可

调用流程

(8) 带有参数的类装饰器,类装饰器修饰类。在flask框架中应用比较多

参数1: 给修饰的类添加成员属性和方法

参数2: 把类中的run方法变成属性

class Kuozhan():

    ad = "贵族茅厕,茅厕中的百岁山."
    
    def money(self):
        print("贵族茅厕,包月1100,一小时200元")
        
    def __init__(self,num):
        self.num = num
        
    def __call__(self,cls):
        print(cls) # MyClass
        if self.num == 1:
            return self.kuozhan1(cls)
        elif self.num == 2:
            return self.kuozhan2(cls)
            
    # 参数1的情况 : 添加成员属性和方法
    def kuozhan1(self,cls):
        def newfunc():
            # MyClass.ad = "贵族茅厕,茅厕中的百岁山."
            cls.ad = Kuozhan.ad
            cls.money = Kuozhan.money
            return cls()            
        return newfunc
        
    # 参数2的情况 : 把方法变成属性;
    def kuozhan2(self,cls):
        def newfunc():
            if "run" in cls.__dict__:
                cls.run = cls.run()
                return cls()
        return newfunc


方式一

@Kuozhan(1) # => @obj => MyClass = obj(MyClass)
class MyClass():
    def run():
        return "亢龙有悔"

obj = MyClass() 
print(obj.ad)
obj.money()

被装饰的类的对象多了方法和属性

返回cls(), 是对象

方式二

@Kuozhan(2)
class MyClass():
    def run():
        return "亢龙有悔"
obj = MyClass()
print(obj.run)

调用分析,此时,类() 实际上是个函数

MyClass()成了函数,那怎么还可以通过对象调用参数, 那是因为又通过cls() 返回回来了

(9)扩展

虽然MyClass2这个名字替换掉了,但是内存中的该类仍然存在;

class MyClass2():
    a = 200

print(id(MyClass2) , "1111111")

def func(cls):
    cls.ad = 90
    print(id(cls),"22222")
    return cls()
obj = func(MyClass2)

MyClass2 = 100
print(MyClass2)
print(obj.a)  # 200 
print(obj.ad) # 90

类是定义的时候就执行类中的代码

函数是调用的时候才执行函数内部的代码


相关文章
|
1月前
|
开发者 Python
探索Python中的装饰器:从基础到高级应用
本文将带你深入了解Python中的装饰器,这一强大而灵活的工具。我们将一起探讨装饰器的基本概念,它们如何工作,以及如何使用它们来增强函数和类的功能,同时不改变其核心逻辑。通过具体代码示例,我们将展示装饰器的创建和使用,并探索一些高级应用,比如装饰器堆栈和装饰带参数的装饰器。无论你是初学者还是有经验的开发者,这篇文章都将为你提供新的视角,帮助你更有效地使用装饰器来简化和优化你的代码。
|
1月前
|
测试技术 数据安全/隐私保护 开发者
探索Python中的装饰器:从基础到高级应用
装饰器在Python中是一个强大且令人兴奋的功能,它允许开发者在不修改原有函数代码的前提下增加额外的功能。本文将通过具体代码示例,带领读者从装饰器的基础概念入手,逐步深入到高级用法,如带参数的装饰器和装饰器嵌套等。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和技巧。
|
1月前
|
开发框架 数据建模 中间件
Python中的装饰器:简化代码,增强功能
在Python的世界里,装饰器是那些静悄悄的幕后英雄。它们不张扬,却能默默地为函数或类增添强大的功能。本文将带你了解装饰器的魅力所在,从基础概念到实际应用,我们一步步揭开装饰器的神秘面纱。准备好了吗?让我们开始这段简洁而富有启发性的旅程吧!
47 6
|
3天前
|
测试技术 数据库 Python
Python装饰器实战:打造高效性能计时工具
在数据分析中,处理大规模数据时,分析代码性能至关重要。本文介绍如何使用Python装饰器实现性能计时工具,在不改变现有代码的基础上,方便快速地测试函数执行时间。该方法具有侵入性小、复用性强、灵活度高等优点,有助于快速发现性能瓶颈并优化代码。通过设置循环次数参数,可以更准确地评估函数的平均执行时间,提升开发效率。
75 61
Python装饰器实战:打造高效性能计时工具
|
3天前
|
设计模式 前端开发 Shell
Python装饰器是什么?
装饰器是Python中用于动态修改函数、方法或类功能的工具,无需改变原代码。通过将函数作为参数传递并返回新函数,装饰器可以在原函数执行前后添加额外逻辑。例如,使用`@logger`装饰器可以打印函数调用日志,而`@timethis`则可用于计算函数执行时间。为了保持被装饰函数的元信息(如`__name__`和`__doc__`),可使用`functools.wraps`装饰器。此外,带参数的装饰器可通过嵌套函数实现,如`@timeitS(2)`,以根据参数条件输出特定信息。
68 59
|
1月前
|
缓存 数据安全/隐私保护 Python
python装饰器底层原理
Python装饰器是一个强大的工具,可以在不修改原始函数代码的情况下,动态地增加功能。理解装饰器的底层原理,包括函数是对象、闭包和高阶函数,可以帮助我们更好地使用和编写装饰器。无论是用于日志记录、权限验证还是缓存,装饰器都可以显著提高代码的可维护性和复用性。
37 5
|
1月前
|
测试技术 Python
探索Python中的装饰器:简化代码,增强功能
在Python的世界中,装饰器是那些能够为我们的代码增添魔力的小精灵。它们不仅让代码看起来更加优雅,还能在不改变原有函数定义的情况下,增加额外的功能。本文将通过生动的例子和易于理解的语言,带你领略装饰器的奥秘,从基础概念到实际应用,一起开启Python装饰器的奇妙旅程。
49 11
|
1月前
|
测试技术 开发者 Python
探索Python中的装饰器:从入门到实践
装饰器,在Python中是一块强大的语法糖,它允许我们在不修改原函数代码的情况下增加额外的功能。本文将通过简单易懂的语言和实例,带你一步步了解装饰器的基本概念、使用方法以及如何自定义装饰器。我们还将探讨装饰器在实战中的应用,让你能够在实际编程中灵活运用这一技术。
44 7
|
1月前
|
Python
探索Python中的装饰器:简化代码,增强功能
在Python的世界里,装饰器就像是给函数穿上了一件神奇的外套,让它们拥有了超能力。本文将通过浅显易懂的语言和生动的比喻,带你了解装饰器的基本概念、使用方法以及它们如何让你的代码变得更加简洁高效。让我们一起揭开装饰器的神秘面纱,看看它是如何在不改变函数核心逻辑的情况下,为函数增添新功能的吧!
|
1月前
|
程序员 测试技术 数据安全/隐私保护
深入理解Python装饰器:提升代码重用与可读性
本文旨在为中高级Python开发者提供一份关于装饰器的深度解析。通过探讨装饰器的基本原理、类型以及在实际项目中的应用案例,帮助读者更好地理解并运用这一强大的语言特性。不同于常规摘要,本文将以一个实际的软件开发场景引入,逐步揭示装饰器如何优化代码结构,提高开发效率和代码质量。
61 6