装饰器:在代码运行期间动态增加功能的方式,称之为装饰器(Decorator)。本质就是函数,功能是为其他函数添加附加功能,

原则:不修改被修饰函数的源代码,不修改被修饰函数的调用方式

装饰器 = 高阶函数 + 函数嵌套 + 闭包

高阶函数

  1. 函数的传入参数是一个函数名
  2. 函数的返回值是一个函数名
  3. 满足上述条件任意一个即为高阶函数

1.传入参数是一个函数名:
可以实现在不修改源代码的情况下为函数添加功能,但是修改了函数的调用方式

def foo():
    print('hello')

def test(func): #高阶函数,传入参数是一个函数名
    print(func) #打印foo的内存地址  <function foo at 0x00000000005C3E18>
    func()      #执行foo函数   hello

test(foo)
import time
def foo():
    time.sleep(1)
    print('hello')

def test(func):
    start_time=time.time()
    func()
    stop_time=time.time()
    print('函数运行时间 %s' %(stop_time - start_time))

test(foo)

# 运行结果
hello
函数运行时间 1.0000572204589844

2.返回值是一个函数名:
可以实现装饰器不修改函数调用方式的功能

def foo():
    print('hello')

def test(func):
    return func

foo = test(foo)     
foo()       
import time
def foo():
    time.sleep(1)
    print('hello')

#不修改foo函数源代码,不修改foo调用方式
def timer(func):
    start_time=time.time()
    func()
    stop_time=time.time()
    print('函数运行时间 %s' %(stop_time - start_time))
    return func

foo = timer(foo)
foo()

# 运行结果
hello
函数运行时间 1.0000572204589844
hello           #会多运行一步

函数嵌套:函数里边定义函数

def foo(name):
    def test():     #函数即变量
        print(name)
    #print(locals())    ##打印当前局部变量(2个) {'test': <function foo.<locals>.test at 0x00000000028A1A60>, 'name': 'hehe'}
    test()
foo('hehe')         #hehe

闭包:函数作用域的一种体现

装饰器基本实现:

import time

def timmer(func):   #func=test
    def wrapper():
        start_time = time.time()
        func()                    #就是运行test()
        stop_time = time.time()
        print('函数运行时间%s' %(stop_time-start_time))
    return wrapper

@timmer          #相当于 test = timmer(test)
def test():
    time.sleep(1)
    print('test函数运行完毕')

# res = timmer(test)   #返回的是wrapper的内存地址
# res()                #执行的是wrapper()

#test = timmer(test)
test()      

装饰器获取原函数返回值

import time

def timmer(func):
    def wrapper():
        start_time = time.time()
        res = func()
        stop_time = time.time()
        print('函数运行时间%s' %(stop_time-start_time))
        return res
    return wrapper

@timmer
def test():
    time.sleep(1)
    print('test函数运行完毕')
    return '这是test函数的返回值'

res = test()    #就是在运行wrapper
print(res)  

加参数:

def timmer(func):
    def wrapper(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)
        stop_time = time.time()
        print('函数运行时间%s' %(stop_time-start_time))
        return res
    return wrapper

@timmer
def test(name,age):
    time.sleep(1)
    print('name is %s,age is %s' %(name,age))
    return '这是test函数的返回值'

test('user',18) 

练习1:使用装饰器为函数加上认证功能

user_list = [
    {'name':'user1','password':'pwd1'},
    {'name':'user2','password':'pwd2'},
    {'name':'user3','password':'pwd3'},
    {'name':'user4','password':'pwd4'}
]
current = {'username':None,'login':False}      #用于判断登录状态信息,避免每个函数都要进行验证的问题

def auth_func(func):
    def wrapper(*args,**kwargs):
        if current['username'] and current['login']:    #如果是登录状态,直接运行函数
            res = func(*args,**kwargs)
            return res
        username = input('用户名:').strip()
        password = input('密码:').strip()
        for user in user_list:
            if username == user['name'] and password == user['password']:
                current['username'] = username      #认证完成后,修改状态信息
                current['login'] = True
                res = func(*args, **kwargs)
                return res
        else:
            print('用户名或者密码错误')
    return wrapper

@auth_func
def index():
    print('welcome')

@auth_func
def home(name):
    print('%s 的个人主页' %name)

index()
home('user1')       

练习2:带参数装饰器

user_list = [
    {'name':'user1','password':'pwd1'},
    {'name':'user2','password':'pwd2'},
    {'name':'user3','password':'pwd3'},
    {'name':'user4','password':'pwd4'}
]
current = {'username':None,'login':False}

def auth(auth_type='filedb'):
    def auth_func(func):
        def wrapper(*args,**kwargs):
            print('认证方式是---->%s' %auth_type)
            if auth_type == 'filedb':
                if current['username'] and current['login']:
                    res = func(*args,**kwargs)
                    return res
                username = input('用户名:').strip()
                password = input('密码:').strip()
                for user in user_list:
                    if username == user['name'] and password == user['password']:
                        current['username'] = username
                        current['login'] = True
                        res = func(*args, **kwargs)
                        return res
                else:
                    print('用户名或者密码错误')
            elif auth_type == 'ldap':
                res = func(*args, **kwargs)
                return res
        return wrapper
    return auth_func

@auth(auth_type='filedb')
def index():
    print('welcome')

@auth(auth_type='ldap')
def home(name):
    print('%s 的个人主页' %name)

index()
home('user1')   
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐