python装饰器(符号@)示例

1. 应用需求

购物车场景,有两个函数get_nameget_info,已实现

def get_name(sess):
    name = sess['name']
    return name


def get_info(sess):
    info = sess['info']
    return info

假设现在接到一个需求,需验证登录后才能获取nameinfo。如果我们在已有源码上直接修改,即添加if语句,这会违反开闭原则(对扩展开放,对修改关闭)。这里介绍Python开发模式中一款强大的工具——装饰器(24种开发模式就是强大)。

2. 装饰器

2.1. 不使用修饰符的方法

直接用代码实现,有

def get_name(sess):
    name = sess['name']
    return name


def get_info(sess):
    info = sess['info']
    return info


def check_for_app_1(func, sess):
    is_login = sess['is_login']
    if is_login:
        return func(sess)
    else:
        return None


def check_for_app_2(func, sess):
    level = sess['level']
    if level > 5:
        return func(sess)
    else:
        return None


if __name__ == '__main__':
	# 接到需求1:需验证是否登录
    sess = {'name': 'app_1.name', 'info': 'app_1.info', 'is_login': True}
    name = check_for_app_1(get_name, sess)
    print(name)
    sess = {'name': 'app_1.name', 'info': 'app_1.info', 'is_login': False}
    name = check_for_app_1(get_name, sess)
    print(name)

	# 中途改需求,接到需求2:转为需验证等级
    sess = {'name': 'app_2.name', 'info': 'app_2.info', 'level': 2}
    name = check_for_app_2(get_name, sess)
    print(name)
    sess = {'name': 'app_2.name', 'info': 'app_2.info', 'level': 10}
    name = check_for_app_2(get_name, sess)
    print(name)

运行结果:
app_1.name
None
None
app_2.name

2.2 使用修饰符符号@的方法

使用更加简便的写法,有

from functools import wraps
# 推荐百度@wraps学习该语句的功能
# 推荐百度*args、**kwargs学习该语句的功能


def check_for_app_1(func):
    @wraps(func)
    def _check(*args, **kwargs):
        # print(args)
        # print(type(args))
        # print(type(args[0]))
        sess = args[0]
        if sess['is_login']:
            return func(*args, **kwargs)
        else:
            return None

    return _check


# 如果需改需求,可添加多一个check_for_app_2方法
# 同时将@check_for_app_1修改成@check_for_app_2
@check_for_app_1
def get_name(sess):
    name = sess['name']
    return name


@check_for_app_1
def get_info(sess):
    info = sess['info']
    return info


if __name__ == '__main__':
    sess = {'name': 'app_1.name', 'info': 'app_1.info', 'is_login': True}
    print(get_name(sess))
    print(get_info(sess))

    sess = {'name': 'app_1.name', 'info': 'app_1.info', 'is_login': False}
    print(get_name(sess))
    print(get_info(sess))

运行结果:
app_1.name
app_1.info
None
None

get_xxx函数不带参数,有

def check_for_app_1(func):
    def _check():
        print('write to log.txt', func.__name__)  # 记录到日志里
        return func()

    return _check


@check_for_app_1
def get_name():
    return 'name'


@check_for_app_1
def get_info():
    return 'info'


if __name__ == '__main__':
    print(get_name())
    print(get_info())

运行结果:
write to log.txt get_name
name
write to log.txt get_info
info

2.3 符号@的有趣用法

符号@的装饰器可以带参数,有

def check_for_app_1(log_path):
    def _check_for_app_1(func):
        def _check(sess):
            print(log_path, end='\t')
            if sess['is_login']:
                return func(sess)
            else:
                return None

        return _check

    return _check_for_app_1


def check_for_app_2(func):
    def _check(sess):
        if sess['level'] >= 3:
            return func(sess)
        else:
            return None

    return _check


# 调用get_name方法时记录到log_name.txt日志中去
@check_for_app_1('D:/log_name.txt')
def get_name(sess):
    name = sess['name']
    return name


# 调用get_info方法时记录到log_app.txt日志中去
# 接到新需求,调用get_info方法时需同时验证登录和等级
@check_for_app_1('D:/log_app.txt')
@check_for_app_2
def get_info(sess):
    info = sess['info']
    return info


if __name__ == '__main__':
    print()

    sess = {'name': 'app_1.name', 'info': 'app_1.info', 'is_login': True, 'level': 5}
    print(get_name(sess))
    print(get_info(sess))
    print()

    sess = {'name': 'app_1.name', 'info': 'app_1.info', 'is_login': False, 'level': 0}
    print(get_name(sess))
    print(get_info(sess))
    print()

    sess = {'name': 'app_2.name', 'info': 'app_2.info', 'is_login': True, 'level': 0}
    print(get_name(sess))
    print(get_info(sess))
    print()

运行结果:

D:/log_name.txt app_1.name
D:/log_app.txt app_1.info

D:/log_name.txt None
D:/log_app.txt None

D:/log_name.txt app_2.name
D:/log_app.txt None

其实上述用法等价于

def check_for_app_1(log_path):
    def _check_for_app_1(func):
        def _check(sess):
            print(log_path, end='\t')
            if sess['is_login']:
                return func(sess)
            else:
                return None

        return _check

    return _check_for_app_1


def check_for_app_2(func):
    def _check(sess):
        if sess['level'] >= 3:
            return func(sess)
        else:
            return None

    return _check


def get_name(sess):
    name = sess['name']
    return name


def get_info(sess):
    info = sess['info']
    return info


if __name__ == '__main__':
    sess = {'name': 'app_1.name', 'info': 'app_1.info', 'is_login': True, 'level': 2}
    # sess = {'name': 'app_1.name', 'info': 'app_1.info', 'is_login': True, 'level': 21}

    get_name_1 = check_for_app_1('E:/log_name.txt')(get_name)
    print(get_name_1(sess))

    get_info_1 = check_for_app_2(get_info)
    get_info_1 = check_for_app_1('E:/log_info.txt')(get_info_1)
    print(get_info_1(sess))

运行结果:
E:/log_name.txt app_1.name
E:/log_info.txt None

3. Reference

python函数修饰符@的使用
手把手带你学会Python

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值