#########################################################

# 装饰器
# 装饰器非常重要,面试Python的公司必问,
# 原则:开放封闭原则 # 开放封闭原则,适用于对已经固定的额功能,和源码,这个原则是为了程序的稳定性,
# 开放就是对已经有的功能的拓展是开放的,
# 封闭就是对已经有的功能是不改动的,

###############    装饰器的初成和开放封闭原则    ##############

# 需求:计算程序执行的时间,

# 第一版:直接在函数的前后增加代码,

# 需求:计算程序执行的时间,
# 第一版:直接在函数的前后增加代码,
import time
def func():
start = time.time() # 这是获取当前的时间戳,#计算时间差使用
time.sleep(1.01)
print(123)
end = time.time()
print(end - start) # 1.0140016078948975,这个时间差就是秒了,
func() # 这种写法有明显的缺点,
# 1,这种不符合开放封闭原则
# 2,这种写法如果有100个函数,你都要加一遍这是不行的,太麻烦了,

# 第二版:写一个函数,然后把需要计算执行时间的函数作为参数传递进去,

# 第二版:写一个函数,然后把需要计算执行时间的函数作为参数传递进去,
def func():
time.sleep(0.01)
print(123)
def timer(f):
start = time.time()
f()
end = time.time()
print(end - start)
timer(func) # 专门写了一个函数用来计算函数的执行时间,

# 第三版:闭包的写法

# 第三版:闭包的写法
def func():
time.sleep(0.01)
print(123)
def timer(f): # 函数作为参数传递进去,就是外部函数的一个变量了,
def inner():
start = time.time()
f() # 这是内部函数引用外部函数的变量,构成一个闭包,
end = time.time()
print(end - start)
return inner
# 这就是一个闭包,因为是函数的嵌套,并且函数内部调用函数外部的参数,
# 不修改函数的调用方式,还想要在函数的前后添加功能,
# timer就是一个装饰器,对函数有装饰作用,
func = timer(func) # inner
func() # inner() # 所以使用装饰器是一个非常不错的方式在不改变程序内部的情况下,在程序的前后添加功能,

###############    最终的装饰器版本    ##############

# 最终的装饰器版本
# 解决两个问题,
# 1是被装饰函数有返回值
# 2是被装饰函数有参数 import time
def timer(f):
def inner(*args, **kwargs): # 这个参数就是为了能接收被装饰器函数的参数,
# 为什么要把参数写到内层函数里面,就是因为,被装饰过的函数已经拿到了inner这个函数名了,下一步调用的是inner
# 所以要给inner传递参数,
start = time.time()
ret = f(*args, **kwargs)
end = time.time()
print(end - start)
return ret # 这个地方要返回是因为被装饰函数可能会有返回值,
# 这个返回值就是被装饰函数的返回值
return inner @timer # func = timer(func) # inner
def func(a):
"""函数"""
time.sleep(0.01)
print(123)
print(a)
return 123
# func = timer(func) # inner
ret = func(1) # inner(),这个地方已经是调用的inner了,所以一定要在inner中把被装饰函数的返回值返回回来,
print(func.__name__) # 这个被装饰器装饰了之后会有问题,inner返回的是inner,而不是func
print(func.__doc__) # 这是none
# print(ret)

装饰器的固定模式:

# 所有有一个装饰器的固定模式
from functools import wraps
def outer(func): # 或者叫做wrapper,这就是装饰器的意思,一般会起一个和业务相关的名字,
@wraps(func) # 加上这一句,再去打印函数的name的时候,就不会是inner了,
def inner(*args, **kwargs): # 一般就是一个inner
# 在被装饰函数之前写的东西
ret = func(*args, **kwargs)
# 在被装饰函数之后写的东西
return ret
return inner @outer # 这一句就是test=outer(test)
def test():
"""
函数测试,
:return:
"""
print(123) test() # 这个地方就是inner()了,就是
print(test.__name__) # 这个被装饰器装饰了之后会有问题,inner返回的是inner,而不是test,@wraps(func)就是解决这个问题,
print(test.__doc__)

注意点:

1,嵌套函数
2,内部引用外部变量
3,返回内部函数的名字
4,被装饰函数的参数
5,被装饰函数的返回值,
6,改变inner的名字,

###############    装饰器进阶--带参数的装饰器    ##############

"""

装饰器进阶
1,带参数的装饰器 场景:就是我写了一个计算代码执行时间的装饰器,然后给每一个函数加上了装饰器,
如果我想要去掉装饰器的时候,就需要一个一个的去掉了,我想要用的时候还需要再一个一个的加上,很麻烦,有什么好的办法? 解决方法:就是给装饰器加上一个参数,然后通过控制参数来判断是否开启装饰器,
参数就叫做flag,
这种代码实现就是使用三层装饰器,这样只需要控制flag就可以控制装饰器是否开启了, """ import time flag = False
def timmer_out(flag):
def timmer(func):
def inner(*args,**kwargs):
if flag:
start = time.time()
ret = func(*args,**kwargs)
end = time.time()
print(end-start)
return ret
else:
ret = func(*args, **kwargs)
return ret
return inner
return timmer @timmer_out(flag)
def test1():
time.sleep(1)
print(123) @timmer_out(flag)
def test2():
time.sleep(1)
print(123) # @timmer:这一句还好理解就是func=timmer(func)
# @timmer_out(flag):为了传递参数,我们可以再次在装饰器外部加一层,用来传递参数,
# 这一句要分开看了,第一步是timmer_out(flag),然后返回了timmer,第二步才是@timmer,执行装饰器, test1()
test2()

###############   装饰器进阶---多个装饰器装饰一个函数    ##############

"""
装饰器进阶:
2,多个装饰器装饰一个函数,
"""
def wrapper1(func):
def inner():
print('wrapper1 ,before func')
func()
print('wrapper1 ,after func')
return inner def wrapper2(func):
def inner():
print('wrapper2 ,before func')
func()
print('wrapper2 ,after func')
return inner @wrapper2
@wrapper1
def f():
print('in f') f()
"""
执行结果:
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
说明了几个问题:
1,多个装饰器是把函数之前的装饰代码都执行之后,然后才是执行被装饰函数,最后是函数之后的装饰代码
2,函数之前的执行顺序是谁在上面执行谁,这是从上到下,函数之后的执行顺序是谁在下面执行谁,这是从下往上,
就像是俄罗斯套娃,进的时候从外往里,出的时候从里往外,
"""

###############################################

############################################

python语法基础-函数-装饰器-长期维护的更多相关文章

  1. python语法基础-并发编程-线程-长期维护

    ###############   线程和GIL,全局解释器锁    ############## """ 线程 为什么会有进程? 主要是能够同时处理多个任务,多个任务还 ...

  2. python基础—函数装饰器

    python基础-函数装饰器 1.什么是装饰器 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能. 装饰器的返回值是也是一个函数对象. 装饰器经常用于有切 ...

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

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

  4. python基础-----函数/装饰器

    函数 在Python中,定义一个函数要使用def语句,依次写出函数名.括号.括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回. 函数的优点之一是,可以将代码块与主程 ...

  5. Python作用域-->闭包函数-->装饰器

    1.作用域: 在python中,作用域分为两种:全局作用域和局部作用域. 全局作用域是定义在文件级别的变量,函数名.而局部作用域,则是定义函数内部. 关于作用域,我要理解两点:a.在全局不能访问到局部 ...

  6. python 修改的函数装饰器

    把好的代码记录下来 方便以后学习 修改的函数参数装饰器 from functools import wraps import time import logging def warn(timeout) ...

  7. python二 总结--函数-- 装饰器

    装饰器是什么? 有什么用? 为什么要用? 真的有用吗? 1.装饰器: 装饰器: 定义:本质是函数,(装饰其他函数)就是为其他函数添加附加功能. 原则:1.不能修改被装饰的函数的源代码          ...

  8. Python中的@函数装饰器到底是什么?

    在解释@函数装饰器之前,先说一下,类中的类方法和静态方法. 在Python中完全支持定义类方法.静态方法.这两种方法很相似,Python它们都使用类来调用(ps:用对象调用也可以). 区别在于:Pyt ...

  9. python 进阶篇 函数装饰器和类装饰器

    函数装饰器 简单装饰器 def my_decorator(func): def wrapper(): print('wrapper of decorator') func() return wrapp ...

随机推荐

  1. 【Python】关于import QtCore报错的处理方法

    刚开始学习使用PyQT,但总碰到一些小挫折 比如 import Pyqt成功 而 from PyQt5 import QtCore, QtGui, QtWidgets却报错,找了半天终于找到资料,原因 ...

  2. 吴裕雄--天生自然TensorFlow2教程:Broadcasting

    Broadcasting可以理解成把维度分成大维度和小维度,小维度较为具体,大维度更加抽象.也就是小维度针对某个示例,然后让这个示例通用语大维度. import tensorflow as tf x ...

  3. linux-权限管理相关

    inux权限管理—基本权限 目录 Linux权限管理—基本权限 一.权限的基本概述 二.权限修改命令chmod 三.基础权限设置案例 四.属主属组修改命令chown Linux权限管理—基本权限 一. ...

  4. POJ 1655 Balancing Act【树的重心模板题】

    传送门:http://poj.org/problem?id=1655 题意:有T组数据,求出每组数据所构成的树的重心,输出这个树的重心的编号,并且输出重心删除后得到的最大子树的节点个数,如果个数相同, ...

  5. Ubuntu的奇技淫巧

    sudo apt-get install cmatrix 输入密码,安装后,按F11把terminal全屏,输入cmatrix -b sudo apt-get install sl 安装后执行sl,屏 ...

  6. uploadifive使用笔记

    官网地址:http://www.uploadify.com/ uploadifive 是基于H5开发,所以支持移动端和PC端 <input type="file" name= ...

  7. PAT Basic 1070 结绳(25) [排序,贪⼼]

    题目 给定⼀段⼀段的绳⼦,你需要把它们串成⼀条绳.每次串连的时候,是把两段绳⼦对折,再如下图所示套接在⼀起.这样得到的绳⼦⼜被当成是另⼀段绳⼦,可以再次对折去跟另⼀段绳⼦串连.每次串 连后,原来两段绳 ...

  8. centos 下使用 pytesseract 识别文字

    偶发一个想法搭一个验证码识别工具,网上查了一下有Tesseract 这个工具可以识别,所以有了后面一小时的搭建过程 ps:Ubuntu 下似乎可以直接用包管理工具来安装,我使用的源码编译安装 前提 由 ...

  9. ZJNU 2204 - dzj的数学作业

    我猜这个数列可以直接从大到小凑…… 推出帕多瓦数列每一项,从大到小循环 遇到小于等于x的项就减掉这一项 全部循环完毕后判断x是否为0即可 #include<stdio.h> typedef ...

  10. linux服务器CentOS7安装node.js

    方维一元夺宝2.0版本,很多用户面临机器人自动执行任务.采集计划一直无法开启的问题. 这个需要开启node.js分享给大家. 1.获取node.js资源 V5.x: curl --silent --l ...