5.初识python装饰器 高阶函数+闭包+函数嵌套=装饰器

一.什么是装饰器?

实际上装饰器就是个函数,这个函数可以为其他函数提供附加的功能。

装饰器在给其他函数添加功能时,不会修改原函数的源代码,不会修改原函数的调用方式。

高阶函数+函数嵌套+闭包 = 装饰器

1.1什么是高阶函数?

1.1.1函数接收的参数,包涵一个函数名。

1.1.2 函数的返回值是一个函数名。

其实这两个条件都很好满足,下面就是一个高阶函数的例子。

def test1():

print "hamasaki ayumi"

def test2(func):

return test1

下面这个代码就满足了对高阶函数所有的条件,

1.1.3 满足以上条件的任意一个条件,就可以称为高阶函数。

如果只是给一个函数添加一个功能,并且不修改原函数的代码,这一点需求,我们通过高阶函数就可以实现,下面是给函数添加一个计算执行时间并不修改函数原有代码的功能。

#!/usr/bin/python2.7

# -*- coding:utf-8 -*-

import time

def foo():

time.sleep(1)

print "hamasaki ayumi <<a best>> 3.28 now on sale!"

def test(func):

start_time = time.time()

func()

stop_time = time.time()

run_time = stop_time - start_time

print run_time

test(foo)

输出结果:

hamasaki ayumi <<a best>> 3.28 now on sale!

1.00331807137

通过上面的测试结果,可以看出,没有修改foo函数的原代码,还给函数增加了一个显示执行时间的功能。

虽然使用高阶函数给原函数foo增加了功能,但是修改了原函数的调用方式,违反了开放封闭原则。

刚刚说了高阶函数接收的参数是一个函数名,我们可以利用这个特性,给函数增加功能(在不修改原代码的前提下)。

那么,高阶函数的另外一个特点,返回值是一个函数,如果应用这种特性,就可以做到不改变函数的调用方式了。那我们就来试一下,只通过高阶函数,是否可以完成装饰器的功能。

import time

def runtime(func):

start_time = time.time()

func()

stop_time = time.time()

run_time = stop_time - start_time

print run_time

return func

def foo():

time.sleep(1)

print "hamasaki ayumi <<a best>> 3.28 now on sale!"

foo = runtime(foo)

foo()

输出结果如下:

hamasaki ayumi <<a best>> 3.28 now on sale!

1.0050868988

hamasaki ayumi <<a best>> 3.28 now on sale!

从得到的结果来看,foo函数被多执行了一次,具体原因,来分析下。

首先调用了runtime(foo),解释器解释到func()的时候,foo函数被执行了一次,runtime函数在return的时候,将foo函数体,return给了foo变量,最后我们在调用foo()的时候,导致foo函数又被多执行了一次,这显然不是我们想要的效果。

所以说,“装饰器”所拥有的功能,单单只通过高阶函数,是无法实现的。

接下来就需要用到剩下的两个知识点了,分别是函数嵌套和函数闭包。

2.什么是函数嵌套?

说到函数嵌套,总会有人以为,在一个函数中调用了另外一个函数,就属于函数嵌套了,就像下面这个例子一样。

def f1():

print ‘f1‘

def f2():

print ‘f2‘

f1()

注意!!这并不是函数嵌套!!

真正的函数嵌套是指,在一个函数中又定义了一个函数。

def f1():

print ‘f1‘

def f2():

print ‘f2‘

print locals()

f1()

像这种在一个函数体内又创建了一个函数,这种形式才属于函数嵌套。

3.什么是闭包函数?

闭包函数,大概可以解释为,在一个内部函数中,对外部作用域(这里的外部作用域指的不是全局作用域!)的变量进行引用,函数内部就可以被理解为是闭包的,下面是一个闭包函数的例子。

a = 1

def f1():

a = 2

def f2():

print a

f2()

f1()

3.1 关于闭包函数的一些使用注意事项。

3.1.1 第一条要注意的就是!闭包函数内部,默认是不可以修改外部作用域的变量的!!(使用nonlocal关键字声明例外)

示例1:

def f1():

x = 1

def f2():

x = 2

print x

print x

f2()

print x

f1()

最后输出的结果是:

1

2

1

在闭包函数中定义的x变量,并没有影响到外部作用域的x变量。

例子2:

def foo():

a = 1

def bar():

a = a + 1

return a

return bar

f = foo()

print f()

分析一下这段代码所存在的问题,在执行foo()函数的时候,python会倒入闭包函数bar,来分析这个作用域的局部变量,其实python在内部规定了,在等号左边的变量都是局部变量,在闭包函数bar中,a赋值在等号的左边,被python认定为这个a是闭包函数bar中的局部变量,在执行print f()时,程序运行到a=a+1的时候,python会在闭包函数bar中找在等号右边的a的值,如果找不到,就报错了。(因为python之前已经把a当做bar闭包函数中的局部变量了。)

那么接下来,我们融合高阶函数+闭包+函数嵌套这三个知识点,来试试看是否可以实现装饰器的功能。

#!/usr/bin/python2.7

# -*- coding:utf-8 -*-

import time

def runtime(func):

def func_in():

start_time = time.time()

func()

stop_time = time.time()

run_time = stop_time - start_time

print run_time

return func_in

def foo():

time.sleep(1)

print "hamasaki ayumi <<a best>> 3.28 now on sale!"

foo = runtime(foo)

foo()

输出的结果:

hamasaki ayumi <<a best>> 3.28 now on sale!

1.00491380692

从结果中可以看出,这次通过上面说的三个知识点,成功初步实现了“装饰器”的功能。

虽然这个通过函数闭包,函数嵌套,高阶函数这三个函数的特性实现了类似装饰器的功能,但是,还是有个小瑕疵,我们看下上个例子的最后两行代码。

foo = runtime(foo)

foo()

如果有很多个函数都要使用前面这个“装饰器”的话,每个函数在调用之前都要重新赋值特别麻烦!

为了更完美的实现装饰器的功能,还需要引入python中的“语法糖”,也就是一个@符号。

这个“@”符号就是python装饰器的语法糖,用法就是@后面加上装饰器的名字,需要使用这个装饰器,“装饰”哪个函数,就把这个装饰器加在函数的上面就可以了。下面是装饰器语法糖的使用示例。

def runtime(func):

def func_in():

start_time = time.time()

func()

stop_time = time.time()

run_time = stop_time - start_time

print run_time

return func_in

@runtime

def foo():

time.sleep(1)

print "hamasaki ayumi <<a best>> 3.28 now on sale!"

foo()

#使用rumtime装饰器,对foo函数做“装饰”。

@runtime = foo = runtime(foo)

这两个语法意义是相同的,只不过不用在每次调用函数之前,都要对函数重新赋值。

本篇文章只是对装饰器的初步了解!关于装饰器的更多内容都在后面的文章中~未完待续~

时间: 2024-08-02 11:02:40

5.初识python装饰器 高阶函数+闭包+函数嵌套=装饰器的相关文章

Python 函数对象、生成器 、装饰器、迭代器、闭包函数

一.函数对象 正确理解 Python函数,能够帮助我们更好地理解 Python 装饰器.匿名函数(lambda).函数式编程等高阶技术. 函数(Function)作为程序语言中不可或缺的一部分,太稀松平常了.但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性.那到底什么是第一类对象(First-Class Object)呢? 在 Python 中万物皆为对象,函数作为第一类对象有如下特性: #函数身为一个对象,拥有对象模型的三个通用属性:id(内存地址

函数式编程 &amp; Python中的高阶函数map reduce filter 和sorted

1. 函数式编程 1)概念 函数式编程是一种编程模型,他将计算机运算看做是数学中函数的计算,并且避免了状态以及变量的概念.wiki 我们知道,对象是面向对象的第一型,那么函数式编程也是一样,函数是函数式编程的第一型.在面向对象编程中,我们把对象传来传去,那在函数式编程中,我们要做的是把函数传来传去,而这个,说成术语,我们把他叫做高阶函数.飞林沙 2)特点 计算视为视为函数而非指令 纯函数式编程:不需变量,无副作用,测试简单(每次的执行结果是一样的) 支持高阶函数,代码简洁 2. python支持

python之6-2高阶函数

1. map函数 map(函数A,字符串或者列表) map函数的意思是将函数A依次作用到字符串的每个字符或者列表的每个元素. 例如: map(lambda x: x*x,[1,2]) [1, 4] 这里lambda是匿名函数,匿名函数的作用就是不用定义函数名. 格式:lambda 参数: exp 关于map函数,其实用的并不是太多,因为可以用列表解析来写,例如上面的等价于[x*x for x in range(1,3)] 2. reduce函数 reduce(函数A,字符串或者列表) reduc

速战速决 (3) - PHP: 函数基础, 函数参数, 函数返回值, 可变函数, 匿名函数, 闭包函数, 回调函数

[源码下载] 作者:webabcd 介绍速战速决 之 PHP 函数基础 函数参数 函数返回值 可变函数 匿名函数 闭包函数 回调函数 示例1.函数的相关知识点 1(基础)function/function1.php <?php /** * 函数的相关知识点 1(基础) */ // 可以在相关的 function 声明语句之前调用该函数 f1(); function f1() { echo "f1"; echo "<br />"; } // 这里调用

python基础6—(高阶,匿名,偏)函数 | 装饰器

这里比较的高级了, 学到这里感觉有点意思,但是也看到了和其他语言相通点 高阶函数 可以把别的函数作为参数传入的函数叫高阶函数 def add(x, y, f): return f(x) + f(y) add(-5, 6, abs) # 11 # 匿名函数 python使用lambda来创建匿名函数 sum = lambda arg1, arg2 : arg1 + arg2 sum(10, 20) # 30 # reduce 内建函数是个二元操作函数, 用来将一个数据集合所有数据进行二元操作 #

【Python基础】高阶函数+函数嵌套+闭包 ==装饰器

高阶函数+函数嵌套+闭包 == 装饰器 一 什么是装饰器 二 装饰器需要遵循的原则 三 实现装饰器知识储备 四 高阶函数 五 函数嵌套 六 闭包 七 无参装饰器 八 装饰器应用示例 九 超时装饰器 参考: https://www.cnblogs.com/linhaifeng/articles/6140395.html https://www.cnblogs.com/haiyan123/p/8387769.html 原文地址:https://www.cnblogs.com/XJT2018/p/11

190401装饰器-高阶函数-闭包

一.装饰器 装饰器本质是函数 为其他函数添加附加功能 不修改被修饰函数的源代码 不修改被修饰函数的调用方式 装饰器示例 import time def timmer(func): def wrapper(*args,**kwargs): start_time = time.time() res = func(*args,**kwargs) stop_time = time.time() print("函数的运行时间:%s" % (stop_time - start_time)) ret

python字符串反转 高阶函数 @property与sorted(八)

(1)字符串反转 1倒序输出 s = 'abcde' print(s[::-1]) #输出: 'edcba' 2 列表reverse()操作 s = 'abcde' lt = list(s) lt.reverse() print(''.join(lt)) #输出: 'edcba' 3 二分法交换位置 s = 'abcde' lt = list(s) for i in range(len(l) // 2): lt[i], lt[-(i+1)] = lt[-(i+1)], lt[i] print('

装饰器之高阶函数

高阶函数概念引入:满足下面两个条件之一便可以称为高阶函数 1:把一个函数的函数名当作实参传给另外一个函数. 2:返回值中包含函数名. 下面是一段简单的高阶函数的代码使用条件1: # Author:Ju BO ''' def bar(): print("in the bar") def test1(func): print(func) #----相当于打印bar这个函数在内存中的门牌号即内存地址 func()#----相当于bar(),调用bar这个函数 test1(bar)#----将