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. 把一个对象转成map对象

    import java.lang.reflect.Field;import java.util.HashMap; public class Util { public static HashMap&l ...

  2. 关于jpa

    mappedBy 如果不写,会多生成一张id关联表,无论是一对多还是多对多,关联表名为两张原始表连接起来,顺序以字母英文排序 名字为类名的小写复数 被标记的类作为被维护者,写入时,需要以维护者repo ...

  3. linux下批量查找UTF-8的BOM文件,并去除BOM

    首先查找看看有哪些文件包含BOM find . -type f -print0 | xargs -0r awk '/^\xEF\xBB\xBF/ {print FILENAME} {nextfile} ...

  4. [UE4]修改瞬移操作方式,默认正前方

    瞬移的时候,如果箭头指向正前方的角度跟中心线相差不大,则可以强制箭头指向中心线. 因为向量也可以表示方向,因此只要只要判断向量长度就是了,判断VectorLength值即可:

  5. centos7 下安装zabbix3.0 agent

    设置YUM源:rpm -ivh http://mirrors.aliyun.com/epel/7/x86_64/Packages/e/epel-release-7-11.noarch.rpmrpm - ...

  6. git学习手记(也许仅对本人有用)

    首先明白git的三种状态 commited已提交 =====>git仓库(存着各种版本)modified已修改(此时就是我们的编辑器中的未保存状态)====>工作目录staged暂存状态= ...

  7. 使用svn创建分支!

    1 在主分支上 右键svn---选中 branch/Tag选项 2,填写新分支目录之后 点击 ok键 3,在新创建的分支目录 右键 --> Chenckout下  就可以把代码拉下来了 4.更新 ...

  8. 微信公众号生成带参数的二维码asp源码下载

    晚上闲着没事,一个朋友联系,让帮忙写一个微信公众号利用asp生成带参数的二维码,别人扫了后如果已经关注过该公众号的,则直接进入公众号里,如果没关注则提示关注,关注后自动把该微信用户资料获取到并且保存入 ...

  9. (转)Mysql哪些字段适合建立索引

    工作中处理数据时,发现某个表的数据达近亿条,所以要为表建索引提高查询性能,以下两篇文章总结的很好,记录一下,以备后用. 数据库建立索引常用的规则如下: 1.表的主键.外键必须有索引: 2.数据量超过3 ...

  10. MyBatis学习总结-MyBatis快速入门的系列教程

    MyBatis学习总结-MyBatis快速入门的系列教程 [MyBatis]MyBatis 使用教程 [MyBatis]MyBatis XML配置 [MyBatis]MyBatis XML映射文件 [ ...