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. Ignite(二): 架构及工具

    1.集群和部署 Ignite集群基于无共享架构,所有的集群节点都是平等的,独立的,整个集群不存在单点故障. 通过灵活的Discovery SPI组件,Ignite节点可以自动地发现对方,因此只要需要, ...

  2. h5互动课件动画如何实现?如何快速开发h5互动课件动画

    最近几年随着h5的兴起,复杂的h5动画,甚至是交互动画类型的产品不断涌现,尤其在课件产品方面,很多公司都有相关需求,最近很多h5开发工程师想了解相关方面的技术. 针对h5,如果是简单的动画效果,可以考 ...

  3. 重置SQLSERVER表的自增列,让自增列重新计数

    SQL的自增列挺好用,只是开发过程中一旦删除数据,标识列就不连续了 写起来 也很郁闷,所以查阅了一下标识列重置的方法 发现可以分为三种: --- 删除原表数据,并重置自增列truncate table ...

  4. Centos 6.4 安装Python 2.7 python-pip

    1. 准备工作 下载源码包 wget http://python.org/ftp/python/2.7.3/Python-2.7.3.tar.bz2 查看是否安装make工具 ~#rpm -qa|gr ...

  5. Windows编程1

    一个最简单的windows必须包括两个函数: 1.入口函数:WinMain 2.窗口过程回调函数:WndProc 结构如下: #include <windows.h> //窗口过程回调函数 ...

  6. Jenkins服务使用nginx代理服务器做负载均衡

    学习nginx代理服务器做负载均衡的使用 在本地安装Nginx 1.下载nginx http://nginx.org/en/download.html         下载稳定版本,以nginx/Wi ...

  7. linux 安装中文支持

    下载  fonts-chinese-3.02-12.el5.noarch.rpm fonts-ISO8859-2-75dpi-1.0-17.1.noarch.rpm 安装各种提示的依赖 安装 chkf ...

  8. Redis集群搭建-韩国庆

    认真一步一步搭建下来,就可以成功.... Redis-cluster集群架构讲解 redis集群专业名词称之为Redis-cluster,redis集群是从3.0版本以后才有的概念,也就是说在3.0之 ...

  9. 找不到visual studio模板信息 解决方法

      菜单->工具->选项->项目和解决方案-> 将"Visual Studio 用户项目模板位置"指向vs安装目录:"E:/Program Fil ...

  10. 数据库事务的四大特性以及事务的隔离级别(mysql)

      本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别. 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性是指 ...