Python 进阶之装饰器

69 阅读3分钟

python进阶

2. 从函数-闭包到装饰器

2.1 函数进阶

2.1.1 函数中定义函数

def functionOne():
    def inner():
        print("this is inner")
    print("this is outer")

内部函数不会自动执行,因为 内部函数根本没有打印,

2.1.2 函数中返回函数

def functionTwo():
    def innerTwo():
        print("this is inner")
    return innerTwo

def test_function():
    functionTwo()()

2.1.3 函数中传入函数

def functionThree(func):
    func()
functionThree(functionOne)

当我们传入参数和返回参数的时候,传入和返回,我们都可以理解为函数名,不需要带括号,我们可以从C语言的角度将 其理解为内存地址,当调用的时候,直接带() 进行直接调用。

2.2 装饰器

2.2.1 如何定义装饰器

先来说一说什么是装饰器:

python中的装饰器就是在不改变原代码的情况下,对原有函数的功能进行扩展

2.3装饰器分类

  • 函数装饰器----用函数写的装饰器

    • 装饰器装饰函数
    • 装饰器装饰类
  • 类装饰器------用类写的装饰器

    • 装饰器装饰函数
    • 装饰器装饰类

2.4 函数装饰器-----装饰函数

从嵌套函数一步一步开始

2.4.1 嵌套函数

def big():
    def small():
        print("======之前输出========")
        f = big()
        print("======之后输出========")
        return f
    return small
​
big()()

2.4.2 最简单的函数装饰器

#一个不传参的函数装饰器
def out(func):
    def inner():
        print("======之前输出========")
        f= func()
        print("======之后输出========")
        return f
    return inner
def task():
    return 3
out(task)()
​
@out        # out= out(note) 他是inner类型,所以我们会发现,当我们打印 print(note)的时候
def note():
    return "sss"
print(note)

我们会发现,装饰器其实就是我们 python 自己 进行的函数调用 只不过使用@符号进行简写

2.4.3 函数有参数

def record(func):
    def link(*args, **kwargs):
        print(*args)
        f = func(*args,**kwargs)
        print(*kwargs)
        return f
    return link
​
@record
def name(a,b):
    return 2
​
name(2,4)

2.4.4 解释器传参

#带参数的函数装饰器
def count_time_args(mas=None):
    def record(func):
        def link(*args, **kwargs):
            print(*args)
            f = func(*args, **kwargs)
            print(*kwargs)
            print("=======当前调用者:========",mas)
            return f
        return link
    return record
​
@count_time_args(mas="baidu")
def test_name(a,b,c):
    print(a,b,c)
​
test_name(3,4,5)

2.5 函数装饰器---装饰类

2.5.1 装饰器不传参

# =====上面全部都是函数装饰器修饰函数,当函数装饰器修饰类时,上面以第一个传入的就不是函数,而是一个类def record(cls):
    def link(*args, **kwargs):
        print(*args,"======")
        f = cls(*args, **kwargs)
        print(*kwargs,"======")
        print("=======当前调用者:========")
        return f
    return link
​
@record
class Tag():
    def __init__(self):
        self.name = "lisi"
        print(self.name)
​
​
​
tag  = Tag()

2.5.2 传参

def count_time_arg(mas=None):
    def record(cls):  #传递的类对象
        def link(*args, **kwargs):    #传递init的参数
            print(*args)
            f = cls(*args, **kwargs)
            print(*kwargs)
            print("=======当前调用者:========",mas)
            return f
        return link
    return record
#如果装饰器需要带参数,我们必须要写括号,不然会报错
@count_time_arg()
class pig():
    def __init__(self):
        self.name = "lisi"
        print(self.name)
​
pig()

我们会发现:两种是一样的,cls和func只不过是一个参数名是没有影响的,参数名可以随便起

2.6 类装饰器

#类装饰器
from datetime import datetime
​
​
class Mark:
    def __init__(self, func):       #传入的是函数对象或者类对象
        self.func = func
        print("=====执行init方法=====")
​
    def __call__(self, *args, **kwargs):
        print("======执行call前======")
        f =self.func(*args,**kwargs)
        print("====执行call方法====")
        return f
​
​
@Mark
def test():
    print("this is a test")
​
test()
​
#类装饰器有参数的时候,init方法传入的参数class MarkTag():
​
    def __init__(self, time = datetime.now()):
        print("this time is {now}".format(now=time))
​
    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print("==========执行前=======")
            res = func(*args,**kwargs)
            print("========执行后=========")
            return res
        return wrapper
​
@MarkTag(333)
def getName():
    print("this is jack")
​
getName()
​
#=====当修饰的是类的是类的时候

其实跟我们的函数只是写法不太一样而已,可以自己手动写一写。