python之装饰器

1. 是什么?

开放原则

软件面试时不可能将所有功能都设计好,当前未来一两年的你需要的功能上线,定期更新迭代,对于软件之前写的源代码一般不会修改,对函数里面的代码以及函数的调用方式。在源码不改变的情况下,增加一些额外的功能。

封闭原则

不要改变源码

python中装饰器: 完美的诠释了开放封闭原则

2. 装饰器的用途

装饰器就是一个函数: 装饰器本身就是一个函数,他要装饰一个函数在不改变原函数的源码以及调用方式的前提下,给其增加一个额外的功能。

登录认证,打印日志

二、初识装饰器

装饰器格式:

def test_time(x):
    def inner():
        start_time = time.time()
        x()
        end_time = time.time()
        print(end_time-start_time)
    return inner

@test_time    # index = test_time(index)
def index():
    time.sleep(2)
    print('欢迎访问博客园首页')
index()

例题:

# 1. 写一个代码测试怼怼哥写的函数的执行效率。
def index():
    time.sleep(2)
    print('欢迎访问博客园首页')


print(time.time())
start_time = time.time()
index()
end_time = time.time()
print(f'此函数的执行效率{end_time-start_time}')
# 2. 主管让你测试小邓,李大象,重复代码太多
def func1():
    time.sleep(2)
    print('欢迎访问日记首页')


def func2():
    time.sleep(1)
    print('欢迎访问评论首页')

start_time = time.time()
func1()
end_time = time.time()
print(f'此函数的执行效率{end_time-start_time}')

start_time = time.time()
func2()
end_time = time.time()
print(f'此函数的执行效率{end_time-start_time}')
# 3. 整合到函数中
def func1():
    time.sleep(2)
    print('欢迎访问日记首页')


def func2():
    time.sleep(1)
    print('欢迎访问评论首页')


def test_time(x):
    start_time = time.time()
    x()
    end_time = time.time()
    print(f'此函数的执行效率{end_time-start_time}')

test_time(func1)
test_time(func2)
# 4. 怼怼哥这个函数在实际项目中被500执行,主管要求:在被执行此函数时,
同时要测试一下被执行函数的效率。


def index():
    time.sleep(2)
    print('欢迎访问博客园首页')

# index()
def test_time(x):
    start_time = time.time()
    x()
    end_time = time.time()
    print(f'此函数的执行效率{end_time-start_time}')

test_time(index)

版本4的问题: 开放原则满足了,封闭原则:不改变原函数的源码,以及调用方式。
违反了封闭原则:改变了函数的调用方式。
# 版本5: 不能改变原函数的调用方式(闭包):


def index():
    time.sleep(2)
    print('欢迎访问博客园首页')

# index()

# def func1():
#     time.sleep(2)
#     print('欢迎访问日记首页')

def test_time(x):  # x = index
    def inner():
        start_time = time.time()
        x()
        end_time = time.time()
        print(f'此函数的执行效率{end_time-start_time}')
    return inner

index = test_time(index)
index()
# 版本6:被装饰函数有返回值

def test_time(x):  # x = index
    def inner():
        start_time = time.time()
        ret = x()
        # print(F'ret: {ret}')
        end_time = time.time()
        print(f'此函数的执行效率{end_time-start_time}')
        return ret
    return inner


@test_time  # index = test_time(index)
def index():
    time.sleep(0.5)
    print('欢迎访问博客园首页')
    return True

print(index())  # inner()
你应该是让True返回给index()这样才完美了,但是现在index是inner,所以你要是完全不改变原函数的使用,
你print(index()) ---> True

# 版本7: 被装饰函数带参数,无论加不加装饰器,你的实参'太白金星'应该传给形参n,。
但版本6不能实现传参,index('太白金星') ==  inner('太白金星')

def test_time(x):  # x = index
    def inner(*args,**kwargs):
        # 函数的定义:* ** 聚合。
        # args = ('苹果')
        #args = (1, 3)
        start_time = time.time()
        ret = x(*args,**kwargs)
        # 函数的执行:* ** 打散。
        # ret = x(*('苹果'))  ==x('苹果',)
        # ret = x(*(1, 3))  ==x(1,3)
        # print(F'ret: {ret}')
        end_time = time.time()
        print(f'此函数的执行效率{end_time-start_time}')
        return ret
    return inner


# @test_time  # index = test_time(index)
def index(n):
    time.sleep(0.5)
    print(f'欢迎{n}访问博客园首页')
    return True

# @test_time  # index = test_time(index)
def func2(a,b):
    time.sleep(0.5)
    print(f'最终结果:{a+b}')
    return a + b


print(index('苹果'))  # inner('苹果')
print(func2(1,3)) # == inner(1,3)


def warpper(f):
    def inner(*args,**kwargs):
        '''被装饰函数之前的操作'''
        # print(666)
        ret = f(*args,**kwargs)
        '''被装饰函数之后的操作'''
        # print('执行完毕了')
        return ret
    return inner

@warpper
def func():
    print(111)
#
func()
func()
func()
func()
func()


装饰器的应用:在不改变原函数的源码以及调用方式前提下,为其增加额外的功能。
登陆认证,打印日志等。

三、被装饰函数带返回值

带返回值是什么?

def test_time(x):
    def inner():
        start_time = time.time()
        ret = x() # 我是新加的参数
        end_time = time.time()
        print(end_time-start_time)
        return ret # 我是新加的参数
    return inner
@test_time
def func1():
    time.sleep(0.5)
    print('欢迎登录博客园首页')
    return True
print(func1())

带返回值的目的?

就是为满足开放封闭原则,使函数更完美

四、被装饰函数带参数

是什么?

函数在不加装饰器的情况下也是要能执行的,加装饰器要不改变原函数的代码

index('太白金星') == inner('太白金星')

def test_time(x):  # x = index
    def inner(*args,**kwargs):
        # 函数的定义:* ** 聚合。
        # args = ('苹果')
        #args = (1, 3)
        start_time = time.time()
        ret = x(*args,**kwargs)
        # 函数的执行:* ** 打散。
        # ret = x(*('苹果'))  ==x('苹果',)
        # ret = x(*(1, 3))  ==x(1,3)
        # print(F'ret: {ret}')
        end_time = time.time()
        print(f'此函数的执行效率{end_time-start_time}')
        return ret
    return inner


# @test_time  # index = test_time(index)
def index(n):
    time.sleep(0.5)
    print(f'欢迎{n}访问博客园首页')
    return True

# @test_time  # index = test_time(index)
def func2(a,b):
    time.sleep(0.5)
    print(f'最终结果:{a+b}')
    return a + b


print(index('苹果'))  # inner('苹果')
print(func2(1,3)) # == inner(1,3)

怎么用?

五、标准版装饰器

是什么?

# 五行
def warpper(f): #定一个一个外层函数
        def inner(*args,**wkargs): #定一个内层函数,支持传入参数,在定义时*起聚合的作用,在执行的时候**起打散的作用
                ret = f(*args,**wkargs)
                return ret
        return inner