分解装饰器(语法糖)

一直有点小迷糊的装饰器,今天看了个视频,觉得讲的很细致,有种豁然开朗的感觉,于是决定梳理一遍记录下来,毕竟好记性不如烂笔头嘛~

一、装饰器的定义:通俗地说,就是装饰其他函数,为其他函数添加附加功能,本质上也是函数。

但要遵循两个原则:
1.不能修改被装饰函数的源代码
2.不能修改被装饰函数的调用方式
简言之,装饰器对被装饰函数是完全透明的。

二、在实现装饰器之前,我们还要先弄明白以下3个知识点:

1.函数即“变量”:在python中,无论是变量还是函数,在定义后,python都会在内存中为其分配一个地址,用来存放变量或函数的内容,在调用该变量或函数时,只要能在内存中找到变量或函数的内存地址,就可以正常运行。
举例来说,

def foo():
    print('in the foo')
    bar()
foo()  # 如果在此刻调用函数foo,就会报错,因为函数bar还没有定义,内存中找不到其内容
def bar():
    print('in the bar')
foo()  # 而在此刻调用函数foo,就可以正常运行,因为调用前,函数bar已正常定义及分配内存地址

2.高阶函数
1) 把一个函数名做为实参传递给另一个函数
(实现在不修改被装饰函数源代码的情况下为其添加附加功能)
举例说明,

import time
def deco(func):
    start_time = time.time()
    func()
    stop_time = time.time()

def test1():
    time.sleep(3)
    print('in the test1')

deco(test1)  # 在不修改test1源代码的情况下,实现了计算函数test1的运行时间

2) 返回值中包含函数名
(实现了不修改被装饰函数的调用方式)

import time
def foo(func):
    print(func)  # 打印的是函数func的内存地址
    return func

def bar():
    time.sleep(3)
    print('in the bar')

bar = foo(bar)  
bar()  # 显然,调用方式没有被改变

3.嵌套函数:在一个函数里再定义另一个函数

def gradpa():
    x=1
    def dad():
        x=2
        def son():
            x=3
            print(x)
        son()
    dad()
gradpa()

输出结果:3

注意:嵌套函数必须是在函数里再定义另一个函数,而高阶函数是调用另一个函数

三、装饰器的实现:高阶函数+嵌套函数
  1. 被装饰函数没有参数
import time

# 装饰器timer
def timer(func):
    def deco():
        start_time = time.time()
            func()
            stop_time = time.time()
            print('the function run time is %s' %(stop_time - start_time))
    return deco

@timer  # 在python里,用@+装饰器函数名,放在被装饰函数上面,实际等同于test1 = timer(test1)
def test1():
    time.sleep(3)
    print('in the test1')

# test1 = timer(test1)  # 结果为deco
test1()  #等同于deco()

2.被装饰函数有0-n个参数
*args:不固定位置参数
**kwargs:关键字参数

import time

# 装饰器timer
def timer(func):
    # 加入*args, **kwargs,无论被装饰函数拥有几个参数,都可以正常运行
    def deco(*args, **kwargs):
        start_time = time.time()
            func(*args, **kwargs)
            stop_time = time.time()
            print('the function run time is %s' %(stop_time - start_time))
    return deco

@timer 
def test2(name):
    time.sleep(3)
    print('in the test2',name)

# test2 = timer(test2)  # 结果为deco
test2('Amy')  #等同于deco('Amy')

3.被装饰函数有返回值

import time

# 装饰器timer
def timer(func):
    def deco(*args, **kwargs):
        start_time = time.time()
            res = func(*args, **kwargs) # 将函数func的返回值赋给res
            stop_time = time.time()
            print('the function run time is %s' %(stop_time - start_time))
            return res # 返回res,就可以将被装饰函数的返回值输出
    return deco

@timer 
def test3(name):
    time.sleep(3)
    print('in the test3',name)
    return 'hello test3'

# test3 = timer(test3)  # 结果为deco
test3('Amy')  #等同于deco('Amy')

4.根据条件给被装饰函数装饰不同功能
举例说明:假设有三个页面,index首页无需登录就能访问,home和bbs页面需要输入正确用户名密码才能进入,且home用本地认证,bbs用远程ldap验证

user = 'amy'
passwd = 'abc123'
# 用户登录认证装饰器
def auth(auth_type): # 第一层,传入不同的验证方式auth_type,返回函数loggin
    def loggin(func): # 第二层,传入被装饰函数func,返回函数deco
        def deco(*args, **kwargs):
            if auth_type == 'local':
                username = input('Username:').strip()
                password = input('Password:').strip()
                if username == user and password == passwd:
                    res = func(*args, **kwargs)
                    return res
                else:
                    exit('Invalid username or password!')
            elif auth_type == 'ldap':
                print('sorry, i don\'t konw ldap')
        return deco
    return loggin

def index():
    print('welcome to index page')

@auth(auth_type='local')  # 执行结果等同于home = deco()
def home():
    print('welcome to home page')

@auth(auth_type='ldap')
def bbs():
    print('welcome to bbs page')

index()
home()
bbs()
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值