题目描述

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 标准库中的装饰器的更多相关文章

  1. 标准库中的装饰器 lru_cache和全新的 singledispatch

    Python 内置了三个用于装饰方法的函数:property.classmethod 和 staticmethod. 另一个常见的装饰器是 functools.wraps,它的作用是协助构建行为 良好 ...

  2. (转)python标准库中socket模块详解

    python标准库中socket模块详解 socket模块简介 原文:http://www.lybbn.cn/data/datas.php?yw=71 网络上的两个程序通过一个双向的通信连接实现数据的 ...

  3. [python]在场景中理解装饰器

    原来我也自己通过查资料,来学习python的装饰器,但是效果不好.因为没有接触过需要用到装饰器的场景,所以 一起的资料都只停留在纸面上,但是今天偶然看到了vimer的这篇文章:http://www.v ...

  4. C++实现python标准库中的Counter

    看python standard library by exmple里面提到一个Counter容器,它像muliset一样,能够维持一个集合,并在常量时间插入元素.查询某个元素的个数,而且还提供了一个 ...

  5. Python标准库中的生成器函数

    一.用于过滤的生成器函数 - 从输入的可迭代对象中产出元素的子集,而不修改元素本身 import itertools l1 = [1,2,3,4,5] l2 = [True,False,True,Fa ...

  6. 06.队列、python标准库中的双端队列、迷宫问题

    class QueueUnderflow(ValueError): """队列为空""" pass class SQueue: def __ ...

  7. python标准库中socket模块详解

    包含原理就是tcp的三次握手 http://www.lybbn.cn/data/datas.php?yw=71 这篇讲到了socket和django的联系 https://www.cnblogs.co ...

  8. 流畅的python第七章函数装饰器和闭包学习记录

    本章讨论的话题 python如何计算装饰器句法 python如何判断变量是不是局部的(通过函数内部是否给变量赋值过来判断是否是局部变量) 闭包存在的原因和工作原理(闭包是一种函数,它会保留定义函数时存 ...

  9. [python标准库]XML模块

    1.什么是XML XML是可扩展标记语言(Extensible Markup Language)的缩写,其中的 标记(markup)是关键部分.您可以创建内容,然后使用限定标记标记它,从而使每个单词. ...

随机推荐

  1. ArrayList实现原理及源码分析之JDK8

    转载 ArrayList源码分析 一.ArrayList介绍 Java 集合框架主要包括两种类型的容器: 一种是集合(Collection),存储一个元素集合. 一种是图(Map),存储键/值对映射. ...

  2. JDBC通过配置文件(properites)读取数据库配置信息

    扫盲: Classloader 类加载器,用来加载 Java 类到 Java 虚拟机中.与普通程序不同的是.Java程序(class文件)并不是本地的可执行程序.当运行Java程序时,首先运行JVM( ...

  3. Elasticsearch之如何合理分配索引分片

    大多数ElasticSearch用户在创建索引时通用会问的一个重要问题是:我需要创建多少个分片? 在本文中, 我将介绍在分片分配时的一些权衡以及不同设置带来的性能影响. 如果想搞清晰你的分片策略以及如 ...

  4. 更改KVM虚拟机root的密码

    今天在使用qemu-kvm安装一个虚拟机,因为已经有一个虚拟机的image文件(qcow2格式的),所以创建虚拟机很简单,直接通过以下命令从image启动就行了. qemu-kvm -cpu host ...

  5. 【LeetCode445】 Add Two Numbers II★★

    题目描述: 解题思路: 给定两个链表(代表两个非负数),数字的各位以正序存储,将两个代表数字的链表想加获得一个新的链表(代表两数之和). 如(7->2->4->3)(7243) + ...

  6. SharePoint中跨列表查询

    1,最近的项目中遇到一个需求,站点中有几十个列表,其中每5,6个列表属于一个模块下的.客户的需求是,首页上显示一个模块下所有列表数据的前5条,并按创建时间排序. 2,刚刚考虑到这块的实现方法时,用的是 ...

  7. Linux用户管理及用户信息查询

    useradd 创建用户,更改用户信息 1.工作原理流程 使用此命令式,若不加任何参数选项,直接跟用户名,那么系统会首先读取/etc/login.defs(用户定义文件)和/etc/default/u ...

  8. 自学tensorflow——2.使用tensorflow计算线性回归模型

    废话不多说,直接开始 1.首先,导入所需的模块: import numpy as np import os import tensorflow as tf 关闭tensorflow输出的一大堆硬件信息 ...

  9. 20155214 2016-2017-2 《Java程序设计》第10周学习总结

    学号 2016-2017-2 <Java程序设计>第10周学习总结 教材学习内容总结 掌握Java Socket编程 理解混合密码系统 掌握Java 密码技术相关API的使用 教材学习中的 ...

  10. 2017-2018-1 20155313 《信息安全系统设计基础》 Myod

    2017-2018-1 20155313 <信息安全系统设计基础> Myod Myod要求 1.复习c文件处理内容 2.编写myod.c 用myod XXX实现Linux下od -tx - ...