python中的类装饰器应用场景_这是我见过最全面的Python装饰器教程了!

装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)。在程序开发中经常使用到的功能,合理使用装饰器,能让我们的程序如虎添翼。

1. 函数名应用

函数名是什么?函数名是函数的名字,本质:变量,特殊的变量。

1 ) 函数名就是函数的内存地址,直接打印函数名,就是打印内存地址

def func1():

print(123)

print(func1)         #

2 ) 函数名可以作为变量

def func1():

print(111)

f = func1

f()           # f() 就是func1()

3 ) 函数名可以作为函数的参数

def func1():

print(111)

def func2(x):

x()

func2(func1)         #func1作为func2的参数

4 ) 函数名可以作为函数的返回值

def wrapper():

def inner():

print('inner')

return inner

f = wrapper()

f()

5 ) 函数名可以作为容器类类型的元素

使用for循环批量执行函数

def func1():

print('func1')

def func2():

print('func2')

def func3():

print('func3')

l1 = [func1,func2,func3]

for i in l1:

i()

像上面函数名这种,叫做第一类对象。

第一类对象( first-class object)指:

1.可在运行期创建

2.可用作函数参数或返回值

3.可存入变量的实体

*不明白?那就记住一句话,就当普通变量用

2. 闭包

1、 闭包函数 : 内部函数包含对外部作用域而非全局作用域变量的引用,该内部函数称为闭包函数

2、闭包的作用:爬虫、装饰器

当程序执行遇到函数执行时,会在内存空间开辟局部命名空间,当函数执行完毕,该命名空间会被销毁。但是如果这个函数内部形成闭包,则该内存空间不会随着函数执行完而消失。

3、如何判断是否是闭包:print(函数名.__closure__) 结果是 cell 说明是闭包,结果是 None 说明不是闭包。

闭包举例

def wrapper():

name = 'summer'

def inner():

print(name)

inner()

wrapper() # summer

如何判断它是否是一个闭包函数呢? 内层函数名.__closure__ cell 就是=闭包

例 1.

def wrapper():

name = 'summer'

def inner():

print(name)

inner()

print(inner.__closure__)

wrapper()

执行输出:

summer

(,)

例 2.

name = 'summer'

def wrapper():

def inner():

print(name)

inner()

print(inner.__closure__)

wrapper()

结果输出:

summer

None

返回值为None 表示它不是闭包,因为name是一个全局变量,如果函数调用了外层变量而非全局变量,那么它就是闭包。

例 3.

name = 'summer'

def wrapper2():

name1 = 'spring'

def inner():

print(name)

print(name1)

inner()

print(inner.__closure__)

wrapper2()

结果输出:

summer

spring

(,)

只要引用了外层变量至少一次,非全局的,它就是闭包

例 4:判断 下面的函数,是一个闭包吗? ******

name = 'summer'

def wraaper2(n):        #相当于n = 'summer'

def inner():

print(n)

inner()

print(inner.__closure__)

wraaper2(name)

结果输出:

summer

(,)

它也是一个闭包. 虽然wraaper2传了一个全局变量,但是在函数wraaper2内部,inner引用了外层变量,相当于在函数inner外层定义了 n = 'summer',所以inner是一个闭包函数

闭包的好处 : 当函数开始执行时,如果遇到了闭包,他有一个机制,他会永远开辟一个内存空间,将闭包中的变量等值放入其中,不会随着函数的执行完毕而消失。

举一个例子:爬3次,内存开了3次,很占用内存

from urllib.request import urlopen

content1 = urlopen('https://www.cnblogs.com/').read().decode('utf-8')

content2 = urlopen('https://www.cnblogs.com/').read().decode('utf-8')

content3 = urlopen('https://www.cnblogs.com/').read().decode('utf-8')

把它封装成闭包

from urllib.request import urlopen

def index():

url = "https://www.cnblogs.com/"

def get():

return urlopen(url).read()

return get        #return的是get,就是一个函数名

cnblog = index()

print(cnblog) # .get at 0x02F46978>

content = cnblog()

print(content) # 页面源码

这个例子,只有第一遍,是从网站抓取的。之后的执行,直接从内存中加载,节省内存空间

3.装饰器

3.1 装饰器初识

装饰器本质: 就是一个python函数,他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。

装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。

import time

def timmer(f):

def inner():

start_time = time.time()

f()

end_time = time.time()

print('此函数的执行时间为{}'.format(end_time - start_time))

return inner

def func1():

print('in func1')

time.sleep(1)

func1 = timmer(func1)

print(func1)

func1()           # 这里的func1是全新的func1,就是上面的赋值,此时相当于执行 inner函数

输出结果:

.inner at 0x03822DF8>

in func1

此函数的执行时间为1.0003533363342285

代码从上至下执行

语法糖: 想测试谁,前面加@装饰器函数,即可。 写装饰器,约定俗成,函数名为wrapper

def wrapper(func):

def inner(*args,**kwargs):

'''被装饰函数之前'''

ret = func(*args,**kwargs)

'''被装饰函数之后'''

return ret

return inner

@wrapper

def func(*args,**kwargs):

print(args,kwargs)

return 666

print(func())

输出结果:

() {}

666

装饰器利用return制造了一个假象,func()执行,其实是执行inner() , func()把原来的func()给覆盖了

3.2 装饰器传参

例 1: 上面装饰器的例子,func1,要传2个参数a,b

import time

def timmer(f):

def inner(a,b):

start_time = time.time()

f(a,b)

end_time = time.time()

print('此函数的执行时间为{}'.format(end_time - start_time))

return inner

@timmer

def func1(a,b):

print('in func1 {}{}'.format(a,b))

time.sleep(1) # 模拟程序逻辑

func1(1,2)

执行输出:

in func1 12

此函数的执行时间为1.0006024837493896

例 2: 如果有多个参数呢?改成动态参数

import time

def timmer(f):

def inner(*args,**kwargs):

start_time = time.time()

f(*args,**kwargs)

end_time = time.time()

print('此函数的执行时间为{}'.format(end_time - start_time))

return inner

@timmer

def func1(*args,**kwargs):

print('in func1 {}{}'.format(args,kwargs))

time.sleep(1) # 模拟程序逻辑

func1(1,2,a='3',b=4)

执行输出:

in func1 (1, 2){'b': 4, 'a': '3'}

此函数的执行时间为1.000101089477539

函数的执行时,*打散 ;

函数的定义时,*聚合。

from functools import wraps

def wrapper(f): # f = func1

def inner(*args,**kwargs):       #聚合,args (1,2,3)

'''执行函数之前的相关操作'''

ret = f(*args,**kwargs)      # 打散 1,2,3

'''执行函数之后的相关操作'''

return ret

return inner

@wrapper # func1 = wrapper(func1) func1 = inner

def func1(*args):       #args (1,2,3) 聚合

print(666)

return args

print(func1(*[1,2,3]))

执行输出:

666

(1, 2, 3)

例 3 *****

import time #1.加载模块

def timmer(*args,**kwargs): #2.加载变量 5.接收参数True,2,3

def wrapper(f): #6.加载变量 8.f = func1

print(args, kwargs) #9.接收timmer函数的值True,2,3

def inner(*args,**kwargs): #10.加载变量. 13.执行函数inner

if flag: #14 flag = True

start_time = time.time() #15 获取当前时间

ret = f(*args,**kwargs) #16 执行func1

time.sleep(0.3) #19 等待0.3秒

end_time = time.time() #20 获取当前时间

print('此函数的执行效率%f' % (end_time-start_time)) #21 打印差值

else:

ret = f(*args, **kwargs)

return ret #22 返回给函数调用者func1()

return inner #11 返回给函数调用者wrapper

return wrapper #7.返回给函数调用timmer(flag,2,3)

flag = True #3 加载变量

@timmer(flag,2,3) # 4.执行函数timmer(flag,2,3) 17.执行函数func1 两步:1,timmer(flag,2,3) 相当于执行wrapper 2.@wrapper 装饰器 func1 = wrapper(func1)

def func1(*args,**kwargs):

return 666 #18 返回给函数调用者f(*args,**kwargs)

print(func1()) #12 执行函数

写装饰器,一般嵌套3层就可以了

3.3 多个装饰器,装饰一个函数

def wrapper1(func): # func == f函数名

def inner1():

print('wrapper1 ,before func') # 2

func()

print('wrapper1 ,after func') # 4

return inner1

def wrapper2(func): # func == inner1

def inner2():

print('wrapper2 ,before func') # 1

func()

print('wrapper2 ,after func') # 5

return inner2

@wrapper2 # f = wrapper2(f) 里面的f==inner1 外面的f == inner2

@wrapper1 # f = wrapper1(f) 里面的f==函数名f 外面的f == inner1

def f(): # 3

print('in f')

f() # inner2()

执行输出:

wrapper2 ,before func

wrapper1 ,before func

in f

wrapper1 ,after func

wrapper2 ,after func

哪个离函数近,哪个先计算 。 最底下的先执行

执行顺序如下图:

多个装饰器,都是按照上图的顺序来的

4. 装饰器的 __name__ 和 __doc___

__name__:函数名

__doc___:函数的解释

普通函数

def func1():

"""

此函数是完成登陆的功能,参数分别是...作用。

return: 返回值是登陆成功与否(True,False)

"""

print(666)

func1()

print(func1.__name__) #获取函数名

print(func1.__doc__) #获取函数名注释说明

执行输出:

666

func1

此函数是完成登陆的功能,参数分别是...作用。

return: 返回值是登陆成功与否(True,False)

这个有什么用呢?比如日志功能,需要打印出谁在什么时间,调用了什么函数,函数是干啥的,花费了多次时间,这个时候,就需要获取函数的有用信息了

带装饰器的函数

def wrapper(f): # f = func1

def inner(*args,**kwargs): #聚合, args (1,2,3)

'''执行函数之前的相关操作'''

ret = f(*args,**kwargs) # 打散 1,2,3

'''执行函数之后的相关操作'''

return ret

return inner

@wrapper

def func1():

"""

此函数是完成登陆的功能,参数分别是...作用。

return: 返回值是登陆成功与否(True,False)

"""

print(666)

return True

func1()

print(func1.__name__)

print(func1.__doc__)

执行输出:

666

inner

执行函数之前的相关操作

函数装饰之后,相当于执行了inner函数,所以输出inner

为了解决这个问题,需要 调用一个模块wraps

wraps将 被修饰的函数(wrapped) 的一些属性值赋值给修饰器函数(wrapper) ,最终让属性的显示更符合我们的直觉

from functools import wraps

def wrapper(f): # f = func1

@wraps(f) #f是被装饰的函数

def inner(*args,**kwargs): #聚合args (1,2,3)

'''执行函数之前的相关操作'''

ret = f(*args,**kwargs) # 打散 1,2,3

'''执行函数之后的相关操作'''

return ret

return inner

@wrapper

def func1():

"""

此函数是完成登陆的功能,参数分别是...作用。

return: 返回值是登陆成功与否(True,False)

"""

print(666)

return True

func1()

print(func1.__name__)

print(func1.__doc__)

执行输出:

666

func1

此函数是完成登陆的功能,参数分别是...作用。

return: 返回值是登陆成功与否(True,False)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/396918.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

对于个人(注册表)与团队(团队表)(两张表没有关联)的展示与可空判断

对于个人&#xff08;注册表&#xff09;与团队(团队表)&#xff08;两张表没有关联&#xff09;的展示与可空判断 1&#xff0c;在Model中只有GroupId没有名称&#xff08;GroupName&#xff09;,所以自己定义一个&#xff1a; /// <summary>/// RegistratorMessage 界面…

macos sierra 引导镜像_真想不到,在win10上可以制作苹果macOS启动U盘

不管你使用的是macOS还是Windows10&#xff0c;电脑出现启动问题是很正常的&#xff0c;原因有很多种&#xff0c;包括(但不限于)文件损坏、硬件故障和错误更新等。如果意外发生在苹果电脑上&#xff0c;可以使用带有安装文件的macOS启动U盘来修复它。这正是在电脑正常工作时应…

搜索引擎使用技巧

一.基本使用 双引号 代表完全匹配搜索&#xff0c;也就是说搜索结果返回的页面包含双引号中出现的所有的词&#xff0c;连顺序也必须完全匹配。bd和Google 都支持这个指令。 例如&#xff1a; “javar高性能程序开发” 减号 代表搜索不包含减号后面的词的页面。使用这个指令时减…

python(1) - 数据类型和变量

数据类型&#xff1a; 整数&#xff1a;就是整数&#xff0c;包括正整数&#xff0c;0&#xff0c;负整数 浮点数&#xff1a; 通俗点说&#xff0c;就是小数 长整数&#xff1a; 就是比较长的整型&#xff0c;通常后面会跟一个L 字符串&#xff1a; 字符串需要用“”或’’括起…

powershell awk_谈谈 PowerShell

万事万物&#xff0c;有始有终。直从萌芽拔&#xff0c;高自毫末始。所谓的 Shell&#xff0c;无非是应用程序与操作系统内核进行交互的一个中间程序而已。我本人玩电脑也有很久一阵子了&#xff0c;最开始接触到的就是Windows 7 操作系统&#xff0c;当时 Windows 7 上市不久&…

设计模式之: 装饰器模式

什么是装饰器模式 作为一种结构型模式, 装饰器(Decorator)模式就是对一个已有结构增加"装饰".适配器模式, 是为现在有结构增加的是一个适配器类,.将一个类的接口&#xff0c;转换成客户期望的另外一个接口.适配器让原本接口不兼容的类可以很好的合作.装饰器模式是将一…

python七段数码管的详解,Python入门基础:七段数码管绘制

1.在学习Python的过程中&#xff0c;运用所学的一些基础知识&#xff0c;进行一些简单的编程&#xff0c;可以收获很多乐趣。在生活中&#xff0c;LED灯无处不在&#xff0c;荧幕显示的广告词&#xff0c;给我们呈现出动态的视觉效果。下面&#xff0c;则以最简单的显示日期为例…

@class

使用格式class 类名; class写在.h文件里&#xff0c;import写在.m文件里。这样可以提高编译效率 import会在导入文件发生变化时重新拷贝编译&#xff0c;而class只会告诉使用者有这个类&#xff0c;并不会去拷贝。 场景1 使用import&#xff1a;a拷贝b&#xff0c;b拷贝c&#…

python图标的演变_Python3 生成icon图标

首先安装所使用的库 pillow&#xff0c; pillow 是用来取代 PIL 的&#xff0c; pip3 install pillow 安装成功图&#xff1a;A866FFD7-2283-4BFB-8313-DBDEE909A579.png 简单的代码&#xff1a; from __future__ import print_function import os, sys from PIL import Image …

IDEA 热部署 仅支持jdk1.6,1.7

第一安装 dcevm 下载地址http://ssw.jku.at/dcevm/binaries/ java -jar dcevm-0.2-win.jar &#xff0c;选择需要安装该补丁的jdk&#xff0c;点击按钮Install即可 第二&#xff1a;IDEA 在Debug模式下运行&#xff0c;这时随便修改文件&#xff0c;自动发布到tomcat中 超级快…

php中perl配置,Windows下 Apache、PHP和Perl的安装配置

在安装AWStats7.0和 JAWStats之前需要配置其环境&#xff0c;而运行AWStats需要perl支持&#xff0c;运行JAWStats需要PHP支持&#xff0c;这篇文章将具体介绍其环境的安装配置。环境Windows 2003Apache2.2Per5.12lPHP5(开源)Apache&#xff1a;http://httpd.apache.org/Perl&a…

Android常用的一些make命令(转载)--不错

原文网址&#xff1a;http://blog.sina.com.cn/s/blog_abc7e49a01011y0n.html 1.make -jXX XX表示数字&#xff0c;这个命令将编译Android系统并生成镜像&#xff0c;XX表示可以使用到的CPU核数&#xff0c;这在配置好的电脑上特别有用&#xff0c;公司的16核ubuntu服务器执行…

arraylist 初始化_ArrayList(JDK1.8)源码解析

既然是看源码&#xff0c;那我们要怎么看一个类的源码呢&#xff1f;这里我推荐的方法是&#xff1a;1)看继承结构看这个类的层次结构&#xff0c;处于一个什么位置&#xff0c;可以在自己心里有个大概的了解。2)看构造方法在构造方法中&#xff0c;看做了哪些事情&#xff0c;…

技术管理:技术负责人所需的四个核心能力

简述 「技术负责人」这一称呼其实比较泛了。往大了讲&#xff0c;可以指 CTO、技术VP、技术总监&#xff0c;往小了讲&#xff0c;可以指 小组Leader、技术主管、架构师 等。 这些不同岗位的「技术负责人」在工作中会处理着各不相同的问题&#xff0c;因此对他能力要求的侧重点…

think php f方法,修改ThinkPHP3.2的F方法

修改ThinkPHP3.2的F方法ThinkPHP3.2的F采用的是序列化方式保存数据&#xff0c;由于F方法保存的文件名是已知的可能造成一些数据泄露&#xff0c;所以在此修改F方法直接替换TP的F方法即可function F($name, $value, $pathDATA_PATH) {static $_cache array();$filename $path…

php Pthread 多线程 (二) Worker和Threaded

<?php //Worker是具有持久化上下文(执行环境)的线程对象 //Worker对象start()后&#xff0c;会执行run()方法&#xff0c;run()方法执行完毕&#xff0c;线程也不会消亡 class MySqlWorker extends Worker {private $name ;private $db null;public function __construct…

ios yymodel 将字典转数组模型_TensorNet——基于TensorFlow的大规模稀疏特征模型分布式训练框架

TensorNet是什么&#xff1f;TensorNet是一个构建在TensorFlow之上针对广告推荐等大规模稀疏场景优化的分布式训练框架。TensorNet的目标是让所有使用TensorFlow的开发者可以快速的、方便的训练出稀疏参数超过百亿的超大模型。训练带有大规模稀疏特征模型的主要挑战在广告、搜索…

mysql 索引及索引创建原则

是什么 索引用于快速的查询某些特殊列的某些行。如果没有索引&#xff0c; MySQL 必须从第一行开始&#xff0c;然后通过搜索整个表来查询有关的行。表越大&#xff0c;查询的成本越大。如果表有了索引的话&#xff0c;那么 MySQL 可以很快的确定数据的位置&#xff0c;而不用查…

php文件怎么制定编码格式,php文件编码格式对结果有影响

最近弄个小网站&#xff0c;发现windows下的文件上传到linux服务器上后&#xff0c;出现了标签错乱的问题。比如&#xff0c;我的代码是&#xff1a;print testtest;但是&#xff0c;浏览器的解析格式缺成了下面的样子:testtest进过不停地搜索&#xff0c;发现了问题所在&#…

【链表】Add Two Numbers

题目&#xff1a; You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list. Input: (2 -> 4 -> 3) (5…