Python语言 标准库中的装饰器
小标 2019-01-17 来源 : 阅读 901 评论 0

摘要:本文主要向大家介绍了Python语言 标准库中的装饰器,通过具体的内容向大家展示,希望对大家学习Python语言有所帮助。

本文主要向大家介绍了Python语言 标准库中的装饰器,通过具体的内容向大家展示,希望对大家学习Python语言有所帮助。

题目描述

1、简单举例 Python 标准库中的装饰器

2、说说你用过的 Python 标准库中的装饰器


1. 首先,我们比较熟悉,也是比较常用的 Python 标准库提供的装饰器有:property,classmethod,staticmethod,functools.wraps四个。这四个的可考点比较多,这里将分别说明:

首先先来说明 functools.wraps,这个我们在之前翻译装饰器时已经谈到过。这里我们同样用代码来说明吧。

# 比如一个简单的用来统计代码运行时长的装饰器
import time
def method_spend(func):
    def inner(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print('[%0.8fs] %s --> %s' % ((end-start), func.__name__, result))
        return result
    return inner
@method_spend
def test():
    print(<span data-raw-text="" "="" data-textnode-index="41" data-index="580" class="character" style=";padding: 0px">"Hello World<span data-raw-text="" "="" data-textnode-index="41" data-index="592" class="character" style=";padding: 0px">")
test()
# outputs:
# Hello World
# [0.00001907s] test --> None
test = test
print(test.__name__)  # inner

从代码可以看出,经过装饰之后,被装饰函数的 name__ 属性被修改了,变成了装饰后的函数。(实际上 __doc 属性也一样被修改了)。而functools.wraps 的作用就是保存被装饰函数的属性。

引用《流畅的Python》中的话
functools.wraps 的作用是协助构建行为良好的装饰器。

使用示例:

import time
import functools
def method_spend(func):
    @functools.wraps(func)  #  使用 functools.wraps
    def inner(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print('[%0.8fs] %s --> %s' % ((end-start), func.__name__, result))
        return result
    return inner
@method_spend
def test():
    print(<span data-raw-text="" "="" data-textnode-index="92" data-index="1213" class="character" style=";padding: 0px">"Hello World<span data-raw-text="" "="" data-textnode-index="92" data-index="1225" class="character" style=";padding: 0px">")
test()
# outputs:
# Hello World
# [0.00001907s] test --> None
test = test
print(test.__name__)  # test

接着我们来谈谈 staticmethod 和 classmethod。这个相对考得比较少,但也需要知道。classmethod 可类比于 JAVA 中的类方法,它第一个参数必须是类对象,而不是类的实例对象。而 staticmethod 作用与 classmethod 类似,可不能过实例对象来调用,但它不强制参数,可以是任何参数。

最后,来简单说下 property 。property 比较重要,后面会再开专题介绍。这里只简单说明它的作用,那就是实现类似 JAVA 中的私有变量的封装,并提供一个获取方法,类似于getXxx 和 setXXX 方法。用代码说话:

# 实现一个简单的 人 类,然后对年龄进行私有化
class Person(object):
    @property
    def age(self):
        return self._age
    # 这样的好处是,可以自定义赋值的逻辑,比如对数据进行某种验证
    @age.setter  # 这里 age 与 @property 包装的函数名一致
    def age(self, value):
        if value > 18:  # 永远18
            value = 18
        self._age = value
p = Person()
p.age = 18  # 实际上调用的是 p.set_age(60)
print(p.age)  # 实际上调用的是 p.get_age()

2. functools.lru_cache 装饰器。从字面来理解,lru 为 <span data-raw-text="" "="" data-textnode-index="145" data-index="2010" class="character" style=";padding: 0px">"Least Recently Used<span data-raw-text="" "="" data-textnode-index="145" data-index="2030" class="character" style=";padding: 0px">"即最近最少使用,cache,不用说,缓存的意思。所以我们就大致知道这个装饰器的作用了,就是缓存部分数据,如果缓存的数据超过限制,就通过 最近最少使用 的规则来淘汰数据。来看一个简单的例子:

# 一个简单的缓存用户的示例
import functools
@functools.lru_cache()
def get_user_info(user_id):
    # 根据用户 id 从数据库获取用户信息,这里简单的输出 id
    print(<span data-raw-text="" "="" data-textnode-index="158" data-index="2250" class="character" style=";padding: 0px">"finding by %s<span data-raw-text="" "="" data-textnode-index="158" data-index="2264" class="character" style=";padding: 0px">" % user_id)
    return user_id
print(get_user_info(1))  # outputs: finding by 1 1
print(get_user_info(1))  # outputs: 1 (可以发现直接拿到了结果)
print(get_user_info(1.0))  # outputs: 1 (可以发现这里没有区分浮点数与整数)
print(get_user_info(2))  # outputs: funding by 2 2

这里需要注意的是, lru_cache 有两个可选的参数配置:

functools.lru_cache(maxsize=128, typed=False)

其中,maxsize 指定可以缓存多少个结果,缓存满了之后,旧的结果被丢弃。一般建议 maxsize 的值是 2 的幂。typed 参数如果设置为 True,会区分不同类型的结果。比如会将 1 和 1.0 区分开。

3. functools.singledispatch 装饰器。这个也比较好理解,它的作用是用来将if…elif..elif…else 这样的代码进行模块化。有点类似于 JAVA 中重载的意味,但又不全是。它是在 Python 3.4 中新增的。我们来看一个简单的例子:

# 一个简单的根据不同类型的数据来进行不同的展示
import functools
@functools.singledispatch
def my_print(obj):
    print(<span data-raw-text="" "="" data-textnode-index="197" data-index="2915" class="character" style=";padding: 0px">"%s -> %s<span data-raw-text="" "="" data-textnode-index="197" data-index="2924" class="character" style=";padding: 0px">" % (obj, type(obj)))
@my_print.register(str)  # 如果是字符串类型,相当于 if isinstance(str_msg, str)
def _(str_msg):
    print(<span data-raw-text="" "="" data-textnode-index="206" data-index="3037" class="character" style=";padding: 0px">"我是str<span data-raw-text="" "="" data-textnode-index="206" data-index="3043" class="character" style=";padding: 0px">")
    print(<span data-raw-text="" "="" data-textnode-index="209" data-index="3055" class="character" style=";padding: 0px">"%s -> %s<span data-raw-text="" "="" data-textnode-index="209" data-index="3064" class="character" style=";padding: 0px">" % (str_msg, type(str_msg)))
@my_print.register(int)  # 如果是字符串类型,相当于 if isinstance(int_msg, int)
def _(int_msg):
    print(<span data-raw-text="" "="" data-textnode-index="218" data-index="3185" class="character" style=";padding: 0px">"我是int<span data-raw-text="" "="" data-textnode-index="218" data-index="3191" class="character" style=";padding: 0px">")
    print(<span data-raw-text="" "="" data-textnode-index="221" data-index="3203" class="character" style=";padding: 0px">"%s -> %s<span data-raw-text="" "="" data-textnode-index="221" data-index="3212" class="character" style=";padding: 0px">" % (int_msg, type(int_msg)))
my_print(<span data-raw-text="" "="" data-textnode-index="224" data-index="3250" class="character" style=";padding: 0px">"haha<span data-raw-text="" "="" data-textnode-index="224" data-index="3255" class="character" style=";padding: 0px">")  # outputs: 我是str haha -> <class 'str'>
my_print(1)  # outputs: 我是int 1 -> <class 'int'>
my_print([1]) # outputs: [1] -> <class 'list'>


本文由职坐标整理并发布,希望对同学们学习Python有所帮助,更多内容请关注职坐标编程语言Python频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程