python装饰器

装饰器

你是一家互联网公司的后端攻城狮,你们公司有一个现有函数如下:

import time
def add(x,y):
    print(x + y)
    time.sleep(5)
#add(5,9)

 

现在TEAM LEADER要让你对函数进行扩展,要求在函数执行之前打印时间,执行之后打印时间,你可能很快就完成了任务,代码如下:

import time
def add(x,y):
    print(time.time())
    print(x + y)
    time.sleep(5)
    print(time.time())
add(5,9)

 

此时你信心满满的把这个代码提交给你的TEAM LEADER审核,没成想,没过5分钟,代码就被打回来了, TEAM LEADER给你反馈是,我现在有很多函数需要加这个功能,你的代码虽然实现了功能,但是需要更改各个函数的代码,这直接违反了软件开发中的一个原则“开放-封闭”原则,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:
封闭:已实现的功能代码块不应该被修改
开放:对现有功能的扩展开放
BUT ANYWAY,老大要求的这个怎么实现呢?如何在不改原有功能代码的情况下
加上认证功能呢?我们之前说过高阶函数,就是把一个函数当做一个参数传给另外一个函数,下面就用高阶函数来实现它

import time
def add(x,y):
    print(x + y)
    time.sleep(5)

定义一个函数
def show_time(f):
def inner(x,y):#***********这里的参数对应函数f的参数
print(time.time())
f(x,y)
print(time.time())
return inner

则执行show_time(add)返回一个函数对象inner
print(show_time(add))#<function show_time.<locals>.inner at 0x0000000001F00268>

函数对象加括号就会执行函数,则
我们将show_time(add)返回的值赋给一个变量add
add = show_time(add)
再执行add,就实现功能了
add(1,2)

 

这样我们在没有修改原函数的前提下,实现了这个功能,此时不管什么函数需要这个功能,你只要:函数名 =  show_time(函数名)  ,然后执行这个函数就可以了,为了代码更加简洁,我们采用注解的方式代替  函数名 =  show_time(函数名),只需要在添加功能的函数上方加一行注解:

import time
def show_time(f):
    def inner(x,y):#***********这里的参数对应函数的参数
        print(time.time())
        f(x,y)
        print(time.time())
    return inner

@show_time
def add(x,y):
print(x + y)
time.sleep(5)
add(5,9)

 

@show_time 就相当于  add = show_time(add),@show_time 就是一个装饰器。
 
装饰器有参数的情况

import time
def logger(flag):#这里参数控制是否打印时间
    def show_time(f):#这里参数对应函数
        def inner(*x, **y):  
# ***********这里的参数对应函数的参数
            start = time.time()
            f(*x, **y)
            end = time.time()
            if flag == True:
                print(end - start)
        return inner
    return show_time
@logger(True)
def add1(*x,**y):
    sum = 0
    for i in x:
        sum += i
    print(sum)
    time.sleep(4)
add1(1,2,3,4,5,6)

 

分析:执行 logger(True)返回show_time
所以  @logger(True)  相当于  @show_time,只是多加了一个条件,让使用变得更加灵活。
 

深浅拷贝
浅拷贝 copy(只拷贝第一层,里面层仍指向原来的对象)

s = [[1, 2], 'aaa', 'bbb']
s2 = s.copy()
#第一层的数据都拷贝一份
s2[0][0] =888
#修改后s[0][0]也会变,他们指向同一个对象
s2[1] = 'www'
#修改后s[1]不会变,各有各的对象
print(s2)
#[[888, 2], 'www', 'bbb']
print(s)
#[[888, 2], 'aaa', 'bbb']

 

深拷贝
需要引入copy模块

import copy
s = [[1, 2], 'aaa', 'bbb']
s3=copy.deepcopy(s)
#所有层都复制一份,各是各的,互不影响。
s3[0][1] = 666
print(s3)
#[[1, 666], 'aaa', 'bbb']
print(s)
#[[1, 2], 'aaa', 'bbb']

 


发表评论