Python装饰器学习(九步入门)

2023-11-07

原文链接: http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html
本文对原文略有改动。。。增加了自己的理解。。。
装饰器其实也就是一个函数,一个用来包装函数的函数,返回一个修改之后的函数对象,将其重新赋值原来的标识符。

1》在函数执行前和执行后分别附加其他的功能

def demo(func):#装饰函数的参数是被装饰的函数对象,返回原函数对象
    print("before myfunc() is called.")
    func()
    print("after myfunc() is called.")
    return func

def myfunc():
    print 'myfunc() is called!'

myfunc()#调用myfunc函数本身
print '------------------' 
myfunc=demo(myfunc)#该语句就是装饰的实质语句!!
print '------------------'
myfunc()#由于demo函数返回的是原函数本身,此处调用的依然是myfunc函数本身
运行结果:
myfunc() is called!
------------------
before myfunc() is called.
myfunc() is called!
after myfunc() is called.
------------------
myfunc() is called!

2》使用语法糖@来装饰函数

def demo(func):#装饰函数的参数是被装饰的函数对象,返回原函数对象
    print("before myfunc() is called.")
    func()
    print("after myfunc() is called.")
    return func
@demo  #程序运行到此处时,以myfunc为实参转去调用demo函数,将demo的返回值赋给myfunc
def myfunc():
    print 'myfunc() is called!'
print '-----------'
myfunc()#由于demo函数返回的是原函数本身,此处调用的依然是myfunc函数本身
运行结果:
before myfunc() is called.
myfunc() is called!
after myfunc() is called.
-----------
myfunc() is called!

3》使用内嵌包装函数来确保新函数被调用

def deco(func):
    def _deco():#内嵌包装函数的形参和返回值与原函数相同
        print("before myfunc() called.")
        result=func()
        print("after myfunc() called.")
        return result
    return _deco #装饰函数返回 内嵌包装函数对象
 
@deco
def myfunc():
    print("myfunc() called.")
    return 'ok'
 
print myfunc()#实际上,调用的是_demo函数
运行结果:
before myfunc() called.
myfunc() called.
after myfunc() called.
ok

4》对带参数的函数进行装饰

def deco(func):
    def _deco(a, b):#内嵌包装函数的形参和返回值与原函数相同
        print("before myfunc() called.")
        result = func(a, b)
        print("after myfunc() called.")
        return result
    return _deco#装饰函数返回内嵌包装函数对象
 
@deco
def myfunc(a,b):
    print("myfunc(%s,%s) called." % (a, b))
    return a + b
 
print myfunc(1, 2)#实际上,调用的是_demo函数
运行结果:
before myfunc() called.
myfunc(1,2) called.
after myfunc() called.
3

5》对参数数量不确定的函数进行装饰

def deco(func):
    def _deco(*args, **kwargs):#参数用(*args,**kwargs),自动适应变参和命名参数
        print("before %s called." % func.__name__)
        result=func(*args, **kwargs)
        print args
        print kwargs
        print("after %s called." % func.__name__)
        return result
    return _deco
@deco
def myfunc(a,b):
    print("myfunc() called.")
    return a+b
@deco
def myfunc1(*args, **kwargs):
    print("myfunc1() called.")

print myfunc(1, 2)
print '-----------'
print myfunc1(3, 4, 5,a=1,b=2)
运行结果:
before myfunc called.
myfunc() called.
(1, 2)
{}
after myfunc called.
3
-----------
before myfunc1 called.
myfunc1() called.
(3, 4, 5)
{'a': 1, 'b': 2}
after myfunc1 called.
None
6》让装饰器带参数

def deco(arg):#和上面示例相比,在外层多了一层包装
    def _deco(func):
        def __deco():
            print("before %s called [%s]." % (func.__name__, arg))
            func()
            print("after %s called [%s]." % (func.__name__, arg))
        return __deco
    return _deco
 
@deco("mymodule")
def myfunc():
    print("myfunc() called.")
 
@deco("mymodule1")
def myfunc1():
    print("myfunc2() called.")
 
myfunc()
myfunc1()
运行结果:
before myfunc called [mymodule].
myfunc() called.
after myfunc called [mymodule].
before myfunc1 called [mymodule1].
myfunc2() called.
after myfunc1 called [mymodule1].

7》让装饰器带 类 参数

class locker:
    def __init__(self):
        print("locker.__init__() should be not called.")    
    @staticmethod
    def acquire():
        print("locker.acquire() called.(这是静态方法)") 
    @staticmethod
    def release():
        print("locker.release() called.(不需要对象实例)")

def deco(cls):
    '''cls 必须实现acquire和release静态方法
       因为装饰器中要调用acquire和release方法,所以类中要定义这2个方法
       之所以定义成静态方法,是因为静态方法可以通过类名来调用,不需要生成实例
    '''
    def _deco(func):
        def __deco():
            print("before %s called [%s]." % (func.__name__, cls))
            cls.acquire()
            try:
                return func()
            finally:
                cls.release()
        return __deco
    return _deco

@deco(locker)
def myfunc():
    print("myfunc() called.")

myfunc()
运行结果:
before myfunc called [__main__.locker].
locker.acquire() called.(这是静态方法)
myfunc() called.
locker.release() called.(不需要对象实例)

8》让装饰器带函数参数

def Filter(before_func,after_func):  
    print before_func  
    print after_func  
    def outer(main_func):  
        print main_func  
        def wrapper(request,kargs):  
            before_result=before_func(request,kargs)  
            if(before_result!=None):  
                return before_result;  
  
            main_result=main_func(request,kargs)  
            if(main_result!=None):  
                return main_result;  
  
            after_result=after_func(request,kargs)  
            if(after_result!=None):  
                return after_result;  
        return wrapper  
    return outer  
  
def before(request,kargs):  
    print request,kargs,'之前!'  
  
def after(request,kargs):  
    print request,kargs,'之后!'  
 
@Filter(before,after)  
def main(request,kargs):  
    print request,kargs  
  
main('hello','python')  
print main  
运行结果:

<function before at 0x02AC7BF0>
<function after at 0x02AC7C30>
<function main at 0x02AC7CF0>
hello python 之前!
hello python
hello python 之后!
<function wrapper at 0x02AC7D30>

9》装饰器带类参数,并分拆公共类到mylocker.py文件中,同时演示了对一个函数应用多个装饰器。。。

mylocker.py文件:

#!/usr/bin/env python
#coding:utf-8
class mylocker:
    def __init__(self):
        print("mylocker.__init__() called.")   
    @staticmethod
    def acquire():
        print("mylocker.acquire() called.")    
    @staticmethod
    def unlock():
        print("mylocker.unlock() called.")

class lockerex(mylocker):
    @staticmethod
    def acquire():
        print("lockerex.acquire() called.")   
    @staticmethod
    def unlock():
        print("lockerex.unlock() called.")

def lockhelper(cls):#参数cls是 类
    '''cls必须实现acquire和unlock静态方法,静态方法可以通过类名来调用,不需要实例'''
    def _deco(func):
        def __deco(*args, **kwargs):
            print("before %s called." % func.__name__)
            cls.acquire()
            try:
                return func(*args, **kwargs)
            finally:
                cls.unlock()
        return __deco
    return _deco
decorator.py文件:

#!/usr/bin/env python
#coding:utf-8
from mylocker import *
class example:
    def __init__(self):
        print '生成一个example类的实例!!'
    @lockhelper(mylocker)
    def myfunc(self):
        print("myfunc() called.")
    @lockhelper(mylocker)
    @lockhelper(lockerex)
    def myfunc1(self, a, b):
        print("myfunc1() called.")
        return a + b
if __name__=="__main__":
    a = example()
    print a
    print '-------------'
    print a.myfunc()
    print '-------------'
    print a.myfunc1(1, 2)
运行decorator.py文件,结果:

生成一个example类的实例!!
<__main__.example instance at 0x02AA2B48>
-------------
before myfunc called.
mylocker.acquire() called.
myfunc() called.
mylocker.unlock() called.
None
-------------
before __deco called.
mylocker.acquire() called.
before myfunc1 called.
lockerex.acquire() called.
myfunc1() called.
lockerex.unlock() called.
mylocker.unlock() called.
3

如果你感觉 “对一个函数应用多个装饰器” 不容易理解,没关系,上边的例子确实有点复杂,

这儿有一个简单的例子可以帮助你理解:python 对一个函数应用多个装饰器

虽然一个函数上面可以有多个装饰器,这种情况一般不推荐使用,因为这种情况下,程序的维护比较困难。。。

(完)



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python装饰器学习(九步入门) 的相关文章

  • 多重处理:如何从子进程重定向标准输出?

    注意 我见过multiprocessing Process 的日志输出 https stackoverflow com questions 1501651 log output of multiprocessing process 不幸的是
  • 如何用spaCy获取依赖树?

    我一直在尝试寻找如何使用 spaCy 获取依赖树 但我找不到任何有关如何获取树的信息 只能在如何导航树 https spacy io usage examples subtrees 如果有人想轻松查看 spacy 生成的依赖关系树 一种解决
  • 蟒蛇 |如何将元素随机添加到列表中

    有没有一种方法可以将元素随机添加到列表中 内置函数 ex def random append lst a lst append b lst append c lst append d lst append e return print ls
  • 将 Django 表单中的所有 CharField 表单字段输入转换为小写

    我使用 Django 表单进行用户注册 用户可以在其中输入优惠券代码 我希望在优惠券代码字段中输入的所有字符都转换为小写 我尝试过在保存方法 自定义清理方法和自定义验证器中使用 lower 但这些方法没有运气 下面是我的代码 class S
  • 无法安装时间模块

    我试过了pip install time and sudo H pip install time 但我不断收到错误 找不到满足要求时间的版本 从 版本 未找到时间匹配的发行版 我正在 PyCharm 中工作 但真正没有意义的是我可以在 Py
  • 如何在 openpyxl 中设置或更改表格的默认高度

    我想通过openpyxl更改表格高度 并且我希望首先默认一个更大的高度值 然后我可以设置自动换行以使我的表格更漂亮 但我不知道如何更改默认高度 唯一的到目前为止 我知道更改表格高度的方法是设置 row dimension idx heigh
  • 使用 Python 解析 XML,解析外部 ENTITY 引用

    在我的 S1000D xml 中 它指定了一个带有对公共 URL 的引用的 DOCTYPE 该 URL 包含对包含所有有效字符实体的许多其他文件的引用 我使用 xml etree ElementTree 和 lxml 尝试解析它并得到解析错
  • 我有一个 Employee 类,我想返回“姓名”列表

    我有一个 Employee 类 我想返回 姓名 列表 雇员 py class Employee object def init self id name members None self id id self name name self
  • Python 相当于 Bit Twiddling Hacks 中的 C 代码?

    我有一个位计数方法 我正在尝试尽可能快地实现 我想尝试下面的算法位摆弄黑客 http graphics stanford edu seander bithacks html CountBitsSetParallel 但我不知道 C 什么是
  • 如何检查包含 NaN 的列表 [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 在我的 for 循环中 我的代码生成一个如下所示的列表 list 0 0 0 0 sum 0 0 0 0 该循环生成所有其他数字向量 但它也
  • 如何像在浏览器中一样检索准确的 HTML

    我正在使用 Python 脚本来呈现网页并检索其 HTML 它适用于大多数页面 但对于其中一些页面 检索到的 HTML 不完整 我不太明白为什么 这是我用来废弃此页面的脚本 由于某种原因 每个产品的链接不在 HTML 中 Link http
  • 将具有不同大小的行的数据加载到 Numpy 数组中

    假设我有一个包含如下数据的文本文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 如何将它加载到 numpy 数组中 使其看起来像这样 1 2 3 4 5 0 6 7 8 0 0 0 9 1
  • Python time.sleep - 永不醒来

    我认为这将是那些简单的问题之一 但它让我感到困惑 停止媒体 我是对的 找到了解决方案 查看答案 我正在使用 Python 的单元测试框架来测试多线程应用程序 很好而且很直接 我有 5 个左右的工作线程监视一个公共队列 以及一个为它们制作工作
  • 将参数传递给 __enter__

    刚刚学习 with 语句尤其是这篇文章 http effbot org zone python with statement htm 问题是 我可以传递一个参数给 enter 我有这样的代码 class clippy runner def
  • 从 Apache 运行 python 脚本的最简单方法

    我花了很长时间试图弄清楚这一点 我基本上正在尝试开发一个网站 当用户单击特定按钮时 我必须在其中执行 python 脚本 在研究了 Stack Overflow 和 Google 之后 我需要配置 Apache 以便能够运行 CGI 脚本
  • django如何将字符串转换为模块?

    我试图了解 django 的另一个神奇之处 它可以将字符串转换为模块 In settings py INSTALLED APPS声明如下 INSTALLED APPS django contrib auth django contrib c
  • dask allocate() 或 apply() 中的变量列名

    我有适用于pandas 但我在将其转换为使用时遇到问题dask 有一个部分解决方案here https stackoverflow com questions 32363114 how do i change rows and column
  • Pandas DataFrame:如何计算组中第一行和最后一行的差异?

    这是我的熊猫数据框 import pandas as pd import numpy as np data column1 338 519 871 1731 2693 2963 3379 3789 3910 4109 4307 4800 4
  • scrapy python 请求未定义

    我在这里找到了答案 code for site in sites Link site xpath a href extract CompleteLink urlparse urljoin response url Link yield Re
  • Python 中的迭代器 (iter()) 函数。 [关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 对于字典 我可以使用iter 用于迭代字典的键 y x 10 y 20 for val in iter y print val 当

随机推荐

  • 两个经典回文字符串问题中的巧妙算法

    问题一 最长回文子串 给定一个字符串 s 找到 s 中最长的回文子串 第一眼的想法是暴力法 由于其时间复杂度高达O n 3 当s过长时效率会特别低 方法一 中心扩展算法 其思想就是遍历一遍字符串 其中在每一个点都进行以其为中心而均匀展开 分
  • 内网隧道搭建ksa工具-端对端-无需公网VPS做流量转发

    1 前言 看雪安全接入 KSA 一款傻瓜式的一键接入私有网络的工具 无论您在任何地点 任何时间 使用任何线路 均可利用这一服务接入自己的私有设备 KSA的服务端和客户端集成在一个可执行文件之中 目前支持Windows macOS和Linux
  • LU分解算法(串行、并行)

    一 串行LU分解算法 详细见MIT线性代数 1 LU分解 矩阵分解 LU分解 分解形式 L 下三角矩阵 U 上三角矩阵 目的 提高计算效率 前提 1 矩阵A为方阵 2 矩阵可逆 满秩矩阵 3 消元过程中没有0主元出现 也就是消元过程中不能出
  • sql ntext數據類型字符替換

    ntext數據類型字符替換 2011 08 21 塗聚文 深圳大運會期間 政府貼出 溫馨提示 交通管制 世界之窗周邊不充許到陽台觀看 出入憑居住證不是身份證 create table tt sid INT IDENTITY 1 1 cont
  • 数据库访问-records库

    records是由requests作者开发的一个DB访问库 与requests的宗旨一样 records也力图成为一个非常易用的DB库 它是基于SQLAlchemy库封装的一个上层库 import records db records Da
  • C++:常见错误LNK2019的几种原因

    转自 https www cnblogs com thisway p 5497200 html error LNK2019问题在VC 6 0中是error LNK2001 unresolved external symbol问题 可能错误号
  • NEUQ OJ 1233: 幸运儿

    题目描述 n 个人围成一圈 并依次编号1 n 从编号为1 的人开始 按顺时针方向每隔一人选出一个 剩下的人重新围成一圈 如此循环直到剩下两人 这剩下的两人就是幸运儿 如果你想成为最后两个幸运儿 请问开始时应该站在什么位置 设3 lt n l
  • 阻止默认事件的方法_React 基础:3种事件绑定方式,避免 this 引用丢失

    前言 这系列是 React 基础教程 参考 React 官网 记录了自己入门学习 React 的笔记 不太适合有 React 丰富经验的同学 但希望看到此文的你 多少都有些收获 文章代码均可在我的码云中找到 https gitee com
  • flutter图片预览_Flutter 视频缩略图

    在做即时通讯前整理了一个视频缩略图的工具类 可供码农直接放入项目中使用 涉及到的插件 video player 0 10 11 2 话不多说代码如下 import package flutter material dart import p
  • Linux系统架构概述

    一 Unix Linux架构 严格意义上 操作系统定义为 控制计算机硬件资源的软件 同时提供坏境让程序可以运行 Linux系统一般有4个主要部分 内核 shell 文件系统和应用程序 内核 shell和文件系统一起形成了基本的操作系统结构
  • 【DahO安装及使用】

    1 安装 Step 1 官网注册帐号 注册地址在这里 注册完毕默认登录 Step 2 点击下载链接 下载你需要的版本 这里 我下载的是DashO的Windows版本 下载完毕后官方会向您发送邮件 复制其中的 key Step 3 下载完毕后
  • 程序员常用的快捷键,你都用到了吗

    Windows系列 Windows M 最小化所有窗口 Windows R 运行某个程序 打开运行窗口 开启运行对话框 Windows E 快速打开我的电脑 Windows L 电脑锁屏 Windows D 显示 恢复桌面 Windows
  • 华为OD机试 - 找终点(Java)

    题目描述 给定一个正整数数组 设为nums 最大为100个成员 求从第一个成员开始 正好走到数组最后一个成员 所使用的最少步骤数 要求 第一步必须从第一元素开始 且1 lt 第一步的步长
  • Java面向对象编程

    下列关于线程的说法错误的是 A 耗时的操作使用线程 提高程序响应 B 耗内存的操作使用线程 提高内存利用率 C 多CPU的系统使用线程 提高CPU利用率 D 并行操作使用线程 如c s架构中服务端程序为每个客户端请求创建一个线程来响应 答案
  • Linux下cppcheck静态检测工具

    1 cppcheck工具说明 cppcheck工具是一个C C 代码缺陷静态检查工具 它不仅可以检查代码中的语法错误 还可以检查出编译器检查不出来的缺陷 从而辅助提升代码质量 2 Linux下cppcheck工具安装 Linux终端输入 s
  • NIO之多路复用

    一 NIO简介 1 Java BIO 同步并阻塞 传统阻塞型 服务器实现模式为一个连接一个线程 即客户端有连接请求时服务器端就需要启动一个线程进行处理 如果这个线程不做任何事情就会造成不必要的开销 2 Java NIO 同步非阻塞 服务器实
  • js高阶函数

    高阶函数特点 1 函数的返回值是一个函数 2 函数的参数是一个函数 回调函数 高阶函数作用 1 将函数的参数预置 2 对函数进行功能扩展 高阶函数应用 闭包是基于高阶函数特性产生的 但高阶函数不一定就是闭包 Promise 函数柯里化 函数
  • react native中ScrollView嵌套TextInput安卓端有滑动问题

    react native中ScrollView嵌套TextInput安卓端有滑动问题 1 1 问题描述 react native中ScrollView嵌套TextInput TextInput组件设置了 textAligin right 后
  • Spring的BeanNameAware和BeanFactoryAware接口

    BeanNameAware 作用 让Bean获取自己在BeanFactory配置中的名字 根据情况是id或者name Spring自动调用 并且会在Spring自身完成Bean配置之后 且在调用任何Bean生命周期回调 初始化或者销毁 方法
  • Python装饰器学习(九步入门)

    原文链接 http www cnblogs com rhcad archive 2011 12 21 2295507 html 本文对原文略有改动 增加了自己的理解 装饰器其实也就是一个函数 一个用来包装函数的函数 返回一个修改之后的函数对