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. centos 7下rabbitmq安装(转)

    安装erlang环境 添加rabbitmq依赖的erlang yum命令repos # In /etc/yum.repos.d/rabbitmq-erlang.repo [rabbitmq-erlan ...

  2. bpmn-js起步

    https://blog.csdn.net/u013253924/article/details/85784002 通过本文逐步熟悉bpmn-js. 快速介绍: bpmn.js是一个BPMN2.0渲染 ...

  3. 防止shell script多次运行

    一个思路是在script初期检测系统中是否存在同名进程. ] then echo "This script is already running. Exit." else whil ...

  4. [原创] JAVA 递归线程池测试 ExecutorService / ForkJoinPool

    测试工具使用递归的方式获取子进程的Msg消息,目前有2种常用的ExecutorService / ForkJoinPool 为了测试哪种效果较好,我们来写个测试Demo,循环5555555次+1(加锁 ...

  5. Git常用的操作记录(自用)

    分支常用操作命令 $ git branch -a //查看分支 $ git checkout -b dev origin/master  //切换/创建分支 $ git branch -vv 或 gi ...

  6. NLP一些工程应用模型

    发现一个DL的博客,对文章分类归纳做的比较好:第三篇文章中的模型可以重点参考 “自然语言学习资料的汇总” 综述 | 一文读懂自然语言处理NLP(附学习资料) 用深度学习(CNN RNN Attenti ...

  7. Spark下的FP-Growth和Apriori

    基本概念 关联分析是一种在大规模数据集中寻找有趣关系的非监督学习算法.这些关系可以有两种形式:频繁项集或者关联规则.频繁项集(frequent item sets)是经常出现在一块的物品的集合,关联规 ...

  8. idea springboot 父子工程 子工程maven不自动import

    父工程删除对spring boot启动项的引用,因为父工程 dependencyManagement,它不会自动加载包,只指定包的版本, 如果在父工程中引用了包,但是没有指定包版本,子工程将不会识别到 ...

  9. CentOS 7修改系统时间及硬件时间

    转载于:https://www.cnblogs.com/LouisZJ/p/8554991.html [root@nginx ~]# timedatectl --help timedatectl [O ...

  10. 在chrome console中添加jQuery

    由于现有seajs等封装,jQuery等已不在全局暴露,即使网站中已使用jQuery,在console也使用不了. 在chrome中可以用以下代码加入jQuery: fetch('http://cod ...