装饰器是十二分重要的高级函数。

参考博客:装饰器

所需前提知识:

1、作用域: LEGB

2、高阶函数

高阶函数是至少满足下列一个条件的函数:

1)接受一个或多个函数作为输入

2)输出一个函数

注意理解:

  • 函数名可以进行赋值
  • 函数名是一个变量,可以作为函数参数以及返回值

函数和我们之前的[1,2,3],'abc',8等一样都是对象,而且函数是最高级的对象(对象是类的实例化,可以调用相应的方法,函数是包含变量对象的对象,牛逼!)。

3、函数的嵌套以及闭包

Python允许创建嵌套函数。通过在函数内部def的关键字再声明一个函数即为嵌套:

def outer():
x = 1 def inner():
print(x) # return inner in_func = outer()
in_func()
in_func()执行的时候outer()函数已经执行完了,为什么inner还可以调用outer里的变量x呢?

这就涉及到我们叫讲的闭包啦!

因为:outer里return的inner是一个闭包函数,有x这个环境变量。

OK,那么什么是闭包呢?

闭包(closure)是函数式编程的重要的语法结构

定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).

如上实例,inner就是内部函数,inner里引用了外部作用域的变量x(x在外部作用域outer里面,不是全局作用域),则这个内部函数inner就是一个闭包。

再稍微讲究一点的解释是,闭包=函数块+定义函数时的环境,inner就是函数块,x就是环境,当然这个环境可以有很多,不止一个简单的x。

装饰器

装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。

概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

假设一个场景:

业务生产中大量调用的函数:

import time

def foo():
print('foo()函数')
time.sleep(2) def bar():
print('bar()函数')
time.sleep(2)

现在有一个新的需求,希望可以记录下函数的执行时间,于是在代码中添加日志代码:

import time
def foo():
start_time=time.time()
print('foo()函数')
time.sleep(2)
end_time=time.time()
print('spend %s'%(end_time-start_time)) foo()

bar()、hello()也有类似的需求,怎么做?再在bar函数里调用时间函数?这样就造成大量雷同的代码,为了减少重复写代码,我们可以这样做,重新定义一个函数:专门设定时间:

import time
def show_time(func):
start_time=time.time()
func()
end_time=time.time()
print('spend %s'%(end_time-start_time))

逻辑上不难理解,而且运行正常。 但是这样的话,你基础平台的函数修改了名字,容易被业务线的人投诉的,因为我们每次都要将一个函数作为参数传递给show_time函数。而且这种方式已经破坏了原有的代码逻辑结构,之前执行业务逻辑时,执行运行foo(),但是现在不得不改成show_time(foo)。那么有没有更好的方式的呢?当然有,答案就是装饰器。

我们需要show_time(foo)返回一个函数对象,而这个函数对象内则是核心业务函数:执行func()与装饰函数时间计算,修改如下:

import time

def show_time(func):
def wrapper():
start_time=time.time()
func()
end_time=time.time()
print('spend %s'%(end_time-start_time)) return wrapper foo=show_time(foo)
foo()

函数show_time就是装饰器,它把真正的业务方法func包裹在函数里面,看起来像foo被上下时间函数装饰了。在这个例子中,函数进入和退出时 ,被称为一个横切面(Aspect),这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。

@符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作

import time

def show_time(func):
def wrapper():
start_time=time.time()
func()
end_time=time.time()
print('spend %s'%(end_time-start_time)) return wrapper @show_time #foo=show_time(foo)
def foo():
print('foo()函数')
time.sleep(2) @show_time #bar=show_time(bar)
def bar():
print('bar()函数')
time.sleep(2) foo()
print('***********')
bar()

如上所示,这样我们就可以省去bar = show_time(bar)这一句了,直接调用bar()即可得到想要的结果。如果我们有其他的类似函数,我们可以继续调用装饰器来修饰函数,而不用重复修改函数或者增加新的封装。这样,我们就提高了程序的可重复利用性,并增加了程序的可读性。

这里需要注意的问题:  foo=show_time(foo)其实是把wrapper引用的对象引用给了foo,而wrapper里的变量func之所以可以用,就是因为wrapper是一个闭包函数。

1、带参数的被装饰函数

1) 定长参数

只需要保持被装饰函数与装饰器中的内部函数参数一致即可

import time

def show_time(func):

    def wrapper(a,b):
start_time=time.time()
func(a,b)
end_time=time.time()
print('spend %s'%(end_time-start_time)) return wrapper @show_time #add=show_time(add)
def add(a,b): time.sleep(1)
print(a+b) add(2,4)

2)不定长参数

import time

def show_time(func):

    def wrapper(*args,**kwargs):
start_time=time.time()
func(*args,**kwargs)
end_time=time.time()
print('spend %s'%(end_time-start_time)) return wrapper @show_time #add=show_time(add)
def add(*args,**kwargs): time.sleep(1)
sum=0
for i in args:
sum+=i
print(sum) add(2,4,8,9)

2、带参数的装饰器

import time

def time_logger(flag=0):

    def show_time(func):

            def wrapper(*args,**kwargs):
start_time=time.time()
func(*args,**kwargs)
end_time=time.time()
print('spend %s'%(end_time-start_time)) if flag:
print('将这个操作的时间记录到日志中') return wrapper return show_time @time_logger(3) # @show_time
def add(*args,**kwargs):
time.sleep(1)
sum=0
for i in args:
sum+=i
print(sum) add(2,7,5)

这里我们又加了一层函数嵌套

@time_logger(3) 做了两件事:

(1)time_logger(3):得到闭包函数show_time,里面保存环境变量flag   这里用到了闭包的知识

(2)@show_time   :add=show_time(add)

上面的time_logger是允许带参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器(一个含有参数的闭包函数)。当我 们使用@time_logger(3)调用的时候,Python能够发现这一层的封装,并把参数传递到装饰器的环境中。

Python3基础笔记--装饰器的更多相关文章

  1. python基础—函数装饰器

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

  2. 十. Python基础(10)--装饰器

    十. Python基础(10)--装饰器 1 ● 装饰器 A decorator is a function that take a function as an argument and retur ...

  3. 笔记||Python3进阶之装饰器

    # 装饰器# 特征: 是用一个@开头的字符串# 装饰器通常用来装饰函数.或者类的方法# 被装饰后的函数,通常是在原有的函数基础上,会多出增加一点功能# 一般来说装饰器本身也是一个函数## def te ...

  4. python3【基础】-装饰器

    要理解充分理解python的装饰器,有充分理解下述三个知识点为前提: python作用域规则 函数即对象 闭包 一.python作用域规则: 首先介绍python中的作用域规则.python的作用域规 ...

  5. 【Python成长之路】python 基础篇 -- 装饰器【华为云分享】

    [写在前面] 有时候看到大神们的代码,偶尔会用到@来装饰函数.当时查了资料,大致了解装饰器一般用于在不改变原函数的基础上 ,对原函数功能进行修改/增强.使用场景是:日志级别设置.权限校验.性能测试等. ...

  6. Python基础之装饰器

    1.什么是装饰器? Python的装饰器的英文名叫Decorator,当你看到这个英文名的时候,你可能会把其跟Design Pattern里的Decorator搞混了,其实这是完全不同的两个东西.虽然 ...

  7. 【python3】 函数 装饰器

    第一步 : 了解装饰器 装饰器模式,重点在于装饰,装饰的核心仍是被装饰的对象. 举一个栗子:我今天穿了一件短袖,但是突然一阵风,短袖没办法为我御寒,我想到的办法是将短袖变得更厚更长,但是改造之后,它就 ...

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

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

  9. python3 如何给装饰器传递参数

    [引子] 之前写过一篇文章用来讲解装饰器(https://www.cnblogs.com/JiangLe/p/9309330.html) .那篇文章的定位是入门级的 所以也就没有讲过多的高级主题,决定 ...

随机推荐

  1. tensorflow入门教程和底层机制简单解说——本质就是图计算,自动寻找依赖,想想spark机制就明白了

    简介 本章的目的是让你了解和运行 TensorFlow! 在开始之前, 让我们先看一段使用 Python API 撰写的 TensorFlow 示例代码, 让你对将要学习的内容有初步的印象. 这段很短 ...

  2. 什么是域名的TTL值? ——一条域名解析记录在DNS缓存服务器中的存留时间

    什么是域名的TTL值? 转自:http://hizip.net/index.php/archives/20/TTL(Time-To-Live),就是一条域名解析记录在DNS服务器中的存留时间.当各地的 ...

  3. javascript系列-class8.BOM

    1.浏览器对象模型( browser object model )   什么是BOM?    提起BOM就不得不提起JavaScript的构成.ECMAScript为JavaScript的核心,但是要 ...

  4. etxjs

    序言 编辑 功能丰富,无人能出其右. 无论是界面之美,还是功能之强,ext的表格控件都高居榜首. 单选行,多选行,高亮显示选中的行,拖拽改变列宽度,按列排序,这些基本功能ExtJS轻量级实现. 自动生 ...

  5. Appserv 2.5.10 升级PHP from version 5.2 to 5.3

    解决方案查看 该文章:http://blog.csdn.net/dull_boy2/article/details/43927363

  6. 51nod 1065 最小正字段和 解决办法:set存前缀和,二分插入和二分查找

    题目: 这题要求大于0的最小字段和,常规O(n)求最大字段和的方法肯定是没法解的. 我的解法是:用sum[i]存前i项的和,也就是前缀和. 这题就变成了求sum[j]-sum[i]的大于0的最小值( ...

  7. js 拼接字符串,table等

    var userTableStr=''; userTableStr +='<table width="750" height="33" border=&q ...

  8. Synchronization (computer science)

    过程同步.数据同步. In computer science, synchronization refers to one of two distinct but related concepts: ...

  9. 路飞学城Python-Day14

    转载:python之路-路飞学城-python-book [25.常用模块-logging模块详解] [26.常用模块-logging模块详解2] [27.常用模块-logging模块日志过滤和日志文 ...

  10. luogu P4018 Roy&October之取石子(博弈论)

    题意 题解 如果n是6的倍数,先手必败,否则先手必胜. 因为6*x一定不是pk 所以取得话会变成6*y+a的形式a=1,2,3,4,5: 然后a一定为质数.我们把a取完就又成为了6*x的形式. 又因为 ...