1、装饰器(decorator):设计模式

作用:给不同的函数和方法,增加不同的公用的功能。

@classmethod,@staticmethod等均是装饰器

定义一个装饰函数,函数必须返回一个闭包函数,并且func(被装饰的函数)会被python自动传递给装饰函数,作为装饰函数的一个参数

2、闭包

函数对象+函数内部需要使用的一个外部变量=函数返回的整体

闭包必须返回函数

装饰函数中的闭包函数结构如下:

def wrapper(*arg,**kw):

  xxxx干一些事情

  func(*arg,**kw)

  yyyy干另外一些事情

return wrapper

1)函数对象与调用函数

>>> sum

<built-in function sum>                #sum是一个内置的函数,不加()是函数对象

#函数对象指的是指向函数所在的内存地址

>>> sum([1,2,3,4])                     #加了括号并且有传参,就是函数调用

10

>>> def pri():

...     return sum                     #函数执行后返回了另外一个函数对象

...

>>> pri()

<built-in function sum>

>>> def func1(func):

...     return func([1,2,3,4])             #函数的参数可以使用函数对象

...                                   #函数对象sum会传给func等价于sum([1,2,3,4])

>>> print(func1(sum))

10

>>> def func1(func):

...     return func([1,2,3,4])

...

>>> func1(sum)

10

>>>

>>> def add(l):                        #l就是返回的[1,2,3,4]

...     result = 0

...     for i in l:

...         result+=i

...     return result

...

>>> func1(add)                       #add函数对象作为一个参数,不用加()

10

2) 闭包模型

def func():                           #定义了函数func()

x = 100                         #定义了一个变量

def func1():                      #在函数func()中又定义了一个函数func1()

print(x)                       #print(x)语句可以访问到x=100变量

return func1                     #func()这个函数返回func1

>>> func()                           #调用func()函数,并未调用到func1,所以返回了

<function func.<locals>.func1 at 0x000001B478F5EE18>#func1的函数对象

>>> a=func()                        #将函数对象赋值给a

>>> a                              #再次打印a时,依然返回函数的内存地址

<function func.<locals>.func1 at 0x000001B478F5EF28>

>>> func()()                         #函数内部调用函数,需要写两个()

100                                 #有调用到func1(),所以会返回100

>>> def func():

...     x = 100

...     def func1():

...        print(x)

...     return func1()               #return的是func1(),函数的调用,所以会进行打印

...

>>> func()

100

>>> a = func()                     #将func()的结果赋值给a

100

>>> a                            #查看a的值返回为空

>>> type(a)                       #a的类型是None,因为100是在func1里的print(x)

<class 'NoneType'>                #打印输出的,但是func1这个函数没有return,默认返回none,func这个函数的返回值是func(),none,所以a的值也是None

闭包部分:

def func():

    x = 100                       #黑体部分是闭包

    def func1():

       print(x)

       return None

return func1

a=func()                          #闭包部分赋值给了a

函数对象+函数内部需要使用的一个外部变量=函数返回的整体

简易版:函数+需要的外部变量,一起返回了

3、查看闭包变量

>>> def func():

...      x = 100

...      def func1():

...         print(x)

...         return None

...      return func1

...

>>> a=func()        #a等价于func1()的内存地址+x=100,作为一个闭包,赋值给了a

>>> a.__closure__

(<cell at 0x000001B478EC8828: int object at 0x000000006FF17760>,)

#int代表闭包里面的变量,int作为闭包变量的一部分返回了

4、闭包的模型:计算一下不同函数的执行时间

1) 一般方法

>>> import time

>>> def a():                             #函数a()的执行时间

...     time1= time.time()

...     i = 1

...     while i<10000000:

...         i+=1

...     time2=time.time()

...     print("time elapsed:%s"%(time2-time1))

...

>>>

>>> def b():                            #函数b()的执行时间

...     time1= time.time()

...     i = 1

...     while i<90000000:

...         i+=1

...     time2=time.time()

...     print("time elapsed:%s"%(time2-time1))

...

>>> a()

time elapsed:0.5356054306030273

>>> b()

time elapsed:4.651560068130493

问:如果是统计100个函数运行的时间,是否代码要重复多次?

2) 通过函数来解决:

>>> def timer(func):           #函数本身作为参数

...     time1= time.time()

...     func()                 #传到函数里面做了一次调用

...     time2=time.time()

...     print("time elapsed:%s"%(time2-time1))

...

>>>

>>>

>>> import time

>>> def a():

...     i = 1

...     while i<10000000:

...         i+=1

...

>>> def b():

...     i = 1

...     while i<90000000:

...         i+=1

...

>>> timer(a)

time elapsed:0.5086383819580078

>>> timer(b)

time elapsed:4.571778774261475

3) 通过装饰器来解决;

import time

def timer(func):                 #装饰函数,装饰器对应的函数必须是闭包函数!!!

def func1():

time1= time.time()

func()

time2=time.time()

print("time elapsed:%s"%(time2-time1))

return func1

#闭包是:func(闭包变量)+func1(闭包函数)

@timer

def a():

i = 1

while i<10000000:

i+=1

@timer

def b():

i = 1

while i<90000000:

i+=1

a()           #a等价于timer(a),由python编译器自动完成的,a()等价于timer(a)()

b()           #b等价于timer(b),由python编译器自动完成的,b()等价于timer(b)()

4) 定义了装饰函数后,调用时也可不用装饰器

import time

def timer(func):                  #定义了装饰函数

def func1():

time1= time.time()       #定义函数调用前做的事儿

func()

time2=time.time()        #定义函数调用后干的事儿

print("time elapsed:%s"%(time2-time1))

return func1

@timer

def a():                   #函数a()使用了装饰器

i = 1

while i<10000000:

i+=1

def b():                  #函数b()未使用装饰函数

i = 1

while i<90000000:

i+=1

print("!")            #仅为了证明函数b被调用

a()                     #a==timer(a),timer(a)(),会调用到func1()

timer(b())               #该方法写的有误,如果想要调用到func1(),()要在外写

b()                   #当有装饰函数,但是没有装饰器时,单独写,无法完成共同的功能,

timer(b)()               #仅仅是对当前函数做了一次调用

运行结果;

E:\>python a.py

time elapsed:1.4122233390808105

!

time elapsed:4.318440914154053

5、作为参数的函数有参数

1) 所有的函数,参数数量都是一样的

import time

def timer(func):

def func1(arg):

time1= time.time()

func(arg)

time2=time.time()

print("time elapsed:%s"%(time2-time1))

return func1

@timer

def a(count):

print("执行次数:",count)

i = 1

while i<count:

i+=1

print("a is over!")

a(20)                  #调用时传的参数等价于func1(arg)中的arg,即20—arg

运行结果:

E:\>python a.py

执行次数: 20

a is over!

time elapsed:0.000997781753540039

2)所有的函数,调用的参数的数量并不是一致的

import time

def timer(func):

def func1(*arg):              #此处的参数需要根据不同的函数动态变化即可变参数

time1= time.time()

func(*arg)               #可变参数可解决问题

time2=time.time()

print("time elapsed:%s"%(time2-time1))

return func1

@timer

def a(count):                    #函数a只有一个参数

print("执行次数:",count)

i = 1

while i<count:

i+=1

print("a is over!")

@timer

def b(count1,count2):              #函数b有两个参数

print("执行次数:",count1+count2)

a(20)

b(1,2)

运行结果;

E:\>python a.py

执行次数: 20

a is over!

time elapsed:0.00196075439453125

执行次数: 3

time elapsed:0.0009877681732177734

3) 传参时,有赋值

import time

def timer(func):

def func1(*arg,**kw):        #**kw可将count==100传入

time1= time.time()

func(*arg,**kw)

time2=time.time()

print("time elapsed:%s"%(time2-time1))

return func1

@timer

def a(count):

print("执行次数:",count)

i = 1

while i<count:

i+=1

print("a is over!")

@timer

def b(count1,count2,count3):

print("执行次数:",count1+count2+count3)

a(20)

b(1,2,count3=100)          #调用函数传参时,有赋值,*arg便不能生效,需要**kw解决

运行结果:

E:\>python a.py

执行次数: 20

a is over!

time elapsed:0.001954793930053711

执行次数: 103

time elapsed:0.0

python入门(十五):装饰器的更多相关文章

  1. python学习笔记(五):装饰器、生成器、内置函数、json

    一.装饰器 装饰器,这个器就是函数的意思,连起来,就是装饰函数,装饰器本身也是一个函数,它的作用是用来给其他函数添加新功能,比如说,我以前写了很多代码,系统已经上线了,但是性能比较不好,现在想把程序里 ...

  2. python基础十之装饰器

    1,装饰器的形成 编程原则:开放封闭原则. 开放:对扩展是开放的 封闭:对修改是封闭的 因为修改是封闭的,所以为了对函数进行功能的扩展,就使用装饰器! 2,装饰器的定义 # wrapper就是一个装饰 ...

  3. 初学 Python(十五)——装饰器

    初学 Python(十五)--装饰器 初学 Python,主要整理一些学习到的知识点,这次是生成器. #-*- coding:utf-8 -*- import functools def curren ...

  4. Python 入门之 Python三大器 之 装饰器

    Python 入门之 Python三大器 之 装饰器 1.开放封闭原则: (1)代码扩展进行开放 ​ 任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改.所以我们必须允许代 ...

  5. Python第十五天 datetime模块 time模块 thread模块 threading模块 Queue队列模块 multiprocessing模块 paramiko模块 fabric模块

    Python第十五天  datetime模块 time模块   thread模块  threading模块  Queue队列模块  multiprocessing模块  paramiko模块  fab ...

  6. python设计模式之内置装饰器使用(四)

    前言 python内部有许多内建装饰器,它们都有特别的功能,下面对其归纳一下. 系列文章 python设计模式之单例模式(一) python设计模式之常用创建模式总结(二) python设计模式之装饰 ...

  7. 孤荷凌寒自学python第二十五天初识python的time模块

    孤荷凌寒自学python第二十五天python的time模块 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 通过对time模块添加引用,就可以使用python的time模块来进行相关的时间操 ...

  8. 孤荷凌寒自学python第十五天python循环控制语句

    孤荷凌寒自学python第十五天python循环控制语句 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) python中只有两种循环控制语句 一.while循环 while 条件判断式 1: ...

  9. Python中利用函数装饰器实现备忘功能

    Python中利用函数装饰器实现备忘功能 这篇文章主要介绍了Python中利用函数装饰器实现备忘功能,同时还降到了利用装饰器来检查函数的递归.确保参数传递的正确,需要的朋友可以参考下   " ...

  10. python函数与方法装饰器

    之前用python简单写了一下斐波那契数列的递归实现(如下),发现运行速度很慢. def fib_direct(n): assert n > 0, 'invalid n' if n < 3 ...

随机推荐

  1. 利用redis List队列简单实现秒杀 PHP代码实现

    一 生产者producer部分 --------------------------------producer 部分注释--------------------------------------- ...

  2. CUDA 编程

    作者:MingChaoSun 原文:https://blog.csdn.net/sunmc1204953974/article/details/51000970 一.CPU和GPU 上图是CPU与GP ...

  3. php.ini文件下载

    该php.ini文件为修改版,完美运行,存于360云盘.

  4. kettle使用小结----脚本启动

    初学kettle,使用kettle Spoon完成转换(ktr)或作业(kjb)的编写之后,执行作业可以在spoon中直接启动,因为我的需求是持续监控数据表的状态进行数据同步, 所以作业任务需要一直在 ...

  5. Caching in Presto

    转自:Caching in Presto Qubole’s Presto-as-a-Service is primarily targeted at Data Analysts who are tas ...

  6. 为什么HTML中的多个空格或是回车在浏览器上只能显示出一个?

    我们在学习HTML的时候可能书本或是老师会告诉我们一件事,就是在HTML中不管我们在两个文本之间加上多少连续的空格或是回车,到了浏览器里面只能显示出一个来.但是我们从来不知道为什么. 原因很简单,因为 ...

  7. NodeJs Fs模块

    和前面的Http.Url模块一样,Fs模块也是node的核心模块之一,主要用于对系统文件及目录进行读写操作. 基本方法 fs.stat fs.stat可以用来判断是文件还是目录:stats.isFil ...

  8. note 11 字典

    字典 Dictionary +什么是字典? +一系列的"键-值(key-value)"对 +通过"键"查找对应的"值" +类似纸质字典,通过 ...

  9. java.lang.Long 类源码解读

    总体阅读了Long的源码,基本跟Integer类类似,所以特别全部贴出源码,直接注释进行理解. // final修饰符 public final class Long extends Number i ...

  10. shell编程简介

    前言 什么是脚本? 脚本简单地说就是一条条的文字命令(一些指令的堆积),这些文字命令是可以看到的(如可以用记事本打开查看.编辑). 常见的脚本: JavaScript(JS,前端),VBScript, ...