python的装饰器概念_python装饰器(一):基础、概念和语法

本文介绍了Python中函数作为一等对象的概念,详细阐述了装饰器的原理和使用,包括如何用函数处理函数、在函数内部定义函数以及装饰器的实现。通过示例展示了如何使用装饰器动态地增强函数功能,如计算运行时间,并探讨了Python的语法糖`@`在装饰器中的作用。最后,文章通过一个实际例子展示了如何创建和应用装饰器来统计函数的执行时间,提高了代码的可读性和可维护性。
摘要由CSDN通过智能技术生成

函数:python中的一等对象

函数也是对象

要想理解装饰器的语法、原理以及运行过程,首先要理解一个概念:在python中,函数是一等对象。

所谓一等对象是指满足一下条件的实体:在运行时创建

能赋值给变量或数据结构中的元素

能作为参数传给函数

能作为函数的返回结果

在Java或者C++中, 整数、字符、数组都是一等对象,这些在python中也不例外,但是在python里函数也是一等对象,同样满足以上条件,因此常被人简称“一等函数”。

举个例子1

2

3

4

5

6

7

8

9

10

11def ():

print('hello world!')

foo()

hello world!

type(foo) # 2

function

foo.__name__ #3

'foo'

以上三部分代码分别表示:foo是一个函数,可以调用

foo是function类的一个实例

foo具有一个属性,名为__name__,即函数名

用函数来处理函数

既然函数也是一等对象,那么既然函数可以用来处理基本类型,自然也就可以用来处理函数。

举个例子:1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18def f():

... '''

... f is a function

... '''

... pass

f.__doc__ # 2

'ntf is a functionnt'

>>>def re_doc(func, doc): # 3

... func.__doc__ = doc

... return func

>>>f = re_doc(f, 'do nothing') # 4

>>> f.__doc__ # 5

'do nothing'定义一个函数f,以及函数说明__doc__

函数说明

定义一个函数,功能是修改一个函数的__doc__属性,参数是一个函数和一个字符串,返回值是一个函数

调用re_doc

f.__doc__被修改了

用函数来处理函数,就是这么简单。

函数内定义函数

既然可以函数内部定义一个变量,那么同样作为python中的一等对象,函数也可以在函数的内部定义1

2

3

4

5

6

7

8

9

10

11

12

13>>>def outer():

... a = 0

...

... def inner(): # 2

... print('inner function')

... inner() # 3

... print('outer function')

>>>outer()

inner function

outer function在函数内部定义一个变量a

在函数内部定义一个函数inner

调用inner

装饰器:用函数修改函数

假如现在有一个需求,需要函数运行结束后打印其运行时间,那么传统的做法又两种,一种是修改函数内部的代码,加入时间统计,二是在调用函数的地方统计。1

2

3

4

5

6

7# 未修改的代码

func1()

func2()

func3()

且不讨论实现这两种方式会影响到代码本身的结构,如果要统计的函数很多,那绝对是一场灾难。1

2

3

4

5

6

7

8

9

10

11

12

13

14# 修改后的代码

start_time = time.time()

func1()

print(time.time() - start_time)

start_time = time.time()

func2()

print(time.time() - start_time)

start_time = time.time()

func3()

print(time.time() - start_time)

既然是修改函数的功能,那我们可以尝试像对待普通变量一样,用函数来处理,也就是今天要讨论的主题——装饰器。

装饰器是一种特殊的函数,可以动态的调整函数(function)、方法(method)和类(class)的功能,而不需要修改其源代码或定义子类。

写一个装饰器

现在我们使用装饰器来实现上述需求1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17>>>import time

>>>def timeit(func):

... def wrapper(*args, **kwargs): # 2

... start_time = time.time()

... result = func(*args, **kwargs)

... print('' %(func.__name__, time.time() - start_time))

... return result

... return wrapper # 3

>>>def f(a, b):

... return a + b

>>>f = timeit(f) # 4

>>>print(f(1, 2))

3定义一个函数(装饰器)

函数内部定义一个新的函数

返回这个函数

将装饰器应用于f

这段代码定义了一个装饰器,将函数传递给该装饰器后,会返回一个新的函数,功能跟原来的函数一致,且增添了统计时间的功能。再之后的使用中,不需要重新编写统计时间的代码。

如果想给新的函数添加统计时间的功能,只需要将这个装饰器应用于这个函数1

2

3

4

5

6

7>>>def f2():

... print('hello world!')

...

>>>f2 = timeit(f2)

>>>f2()

hello world!

语法糖

语法糖(Syntactic sugar)是指对语言的功能没有影响,但是会方便程序员使用的语法。

根据上面的例子,如果想对一个函数应用decorater,需要这样写:1

2>>>def f(): pass

>>>f = decorater(f)

python针对装饰器提供了一个语法糖1

2>>>@decorater

...def f(): pass

二者的作用是一样的,将装饰器应用到函数f上

并且使用@会有一些好处,使用原有的方式时,将应用装饰器的语句f = decorator(f)放到函数体下面时,如果函数体过长,函数的声明语句与装饰器语句距离很远,有损代码的可读性。

如果对一个函数使用多个装饰器,,如果不用@,有以下两种方式1

2

3

4

5

6# 方式一

f = decorator1(f)

f = decorator2(f)

# 方式二

f = decorator2(decorator1(f))

而使用@,代码的可读性与可维护性都比上述两种方式更高1

2

3@decorator1

@decorator2

def f():

总结

由于python中的函数可以作为函数的参数和返回值,使得python中出现一种特殊的函数——装饰器。可以在不修改函数源码的情况下,增强函数的功能。语法糖@使得对函数使用装饰器变得更简单清晰。行香子·过七里濑

苏轼

一叶舟轻,双桨鸿惊。水天清、影湛波平。

鱼翻藻鉴,鹭点烟汀。过沙溪急,霜溪冷,月溪明。

重重似画,曲曲如屏。算当年、虚老严陵。

君臣一梦,今古空名。但远山长,云山乱,晓山青。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值