iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >python 装饰器理解
  • 516
分享到

python 装饰器理解

python 2023-01-31 06:01:51 516人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

在理解装饰器之前,先应该对闭包有个概念:所谓闭包,就是将组成函数的语句和这些语句的执行环境打包在一起时得到的对象,它的主要作用是封存上下文。这一特性可以巧妙的被用于现有函数的包装,从而为现有函数添加功能,这就是装饰器。装饰器的本质与作用装饰

在理解装饰器之前,先应该对闭包有个概念:所谓闭包,就是将组成函数的语句和这些语句的执行环境打包在一起时得到的对象,它的主要作用是封存上下文。这一特性可以巧妙的被用于现有函数的包装,从而为现有函数添加功能,这就是装饰器。

装饰器的本质与作用

装饰器(Decorator)的本质是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象。

它经常用于有切面需求的场景 ,比如:插入日志性能测试事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续复用。

我们先看一个例子,代码如下:

1

2

3

4

#!/usr/bin Python

 

def foo():

print('i am foo')

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

1

2

3

def foo():

print('i am foo')

logging.info("foo is running")

此时bar()、bar2()也有类似的需求,再写一个logging在bar函数里?为了提高代码的复用,我们重新定义一个函数:专门处理日志,日志处理完后再执行真正的业务代码:

1

2

3

4

5

6

7

8

9

10

#!/usr/bin python

 

def use_logging(func):

logging.warn("%s is running" % func.__name__)

func()

 

def bar():

print('i am bar')

 

use_logging(bar)

上述代码虽然解决了,但是我们每次都要将一个函数作为参数传递给use_logging函数,而且这种方式以已经破坏了原有的代码逻辑结构,本来的业务逻辑是执行bar(),但是现在不得已改成执行use_logging(bar)。鉴于这个弊端,Python装饰器应运而生。

简单装饰器

函数use_logging就是装饰器,它把执行真正业务方法的func包裹在函数里面,看起来像bar被use_logging装饰了。

1

2

3

4

5

6

7

8

9

10

11

def use_logging(func):

def wrapper(*args,**kwargs):

logging.warn("%s is running" % func.__name__)

return func(*args,**kwargs)

return wrapper

 

def bar():

print('i am bar')

 

bar = use_logging(func)

bar()

在这个例子中,函数进入和退出时,被称为一个横切面(Aspect),这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。

但是bar = use_logging(func)这样的写法未免太过麻烦,于是Python提供了一种更优雅的写法:语法糖。@符号是装饰器的语法糖,在定义函数时使用,避免了再一次赋值操作。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

def use_logging(func):

def wrapper(*args,**kwargs):

logging.warn("%s is running" % func.__name__)

return func(*args)

return wrapper

 

@use_logging # 语法糖,等价于:bar=use_logging(bar)

def foo():

print('i am foo')

 

@use_logging

def bar():

print('i am bar')

bar()

如上所示,直接调用bar()就可以获得结果。如果有其他类似函数,也可以继续调用装饰函数,而不用重复修改或增加新的封装。

装饰器在Python使用如此方便都要归因于Python函数能像普通的对象(Python中一切皆对象)一样作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以定义在另一个函数内。

带参数的装饰器

在上述的的装饰器调用中,@use_logging该装饰器唯一的参数就是执行业务的函数,而装饰器的语法允许我们在调用时,提供其他参数,比如:@decorator(a),这样,就为装饰器的编写和使用提供了更大的灵活性。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

def use_logging(level):

def decorator(func):

def wrapper(*args,**kwargs):

if level == "warn":

logging.warn("%s is running" % func.__name__)

return func(*args)

return wrapper

return decorator

 

@use_logging(level = "warn")

def foo(name = 'foo')

print("i am %s" % name)

 

foo()

上述的use_logging是允许带参数的装饰器,是对原有装饰器的一次函数封装,并返回一个装饰器。我们可以将它理解为一个含有参数的闭包,当我们调研这个语法糖的时候,Python会发现这一层的封装,并将参数传递到装饰器的环境中。

总结:无参的装饰器参数是要装饰的函数;有参装饰器参数是函数的参数,最后返回的是内部函数。

类装饰器

相比函数装饰器,类装饰器具有高内聚、灵活性大、高封装等优点。使用类装饰器还可以依靠类内部的__call__方法,当使用@将装饰器附加到函数上时 ,就会调用此方法。

1

2

3

4

5

6

7

8

9

10

11

12

13

class foo(object):

def __init__(self,func):

self._func = func

 

def __call__(self):

print('class decorator running')

self._func()

print('class decorator ending')

@foo

def bar():

print('i am bar')

 

bar()

使用类装饰器极大地复用了代码,但是它也存在缺陷:原函数的元信息不见了,比如函数的docstring、__name__、参数列表,我们先写一个装饰器:

1

2

3

4

5

def logged(func):

def with_logging(*args,**kwargs):

print func.__name__+"was called"

return func(*args,**kwargs)

return with_logging

定义一个函数来调用该装饰器:

1

2

3

4

@logged

def f(x):

"""does some math"""

return x+x*x

上述函数完全等价于:

1

2

3

4

def f(x):

"""does some math"""

return x+x*x

f = logged(f)

可以看出,函数f被with_logging取代了,因此它的docstring、__name__也就变成了with_logging函数的信息了:

1

2

print f.__name__   # print 'with_logging'

print f.__doc__    # print None

好在我们有functools.wraps(Python的一个模块),wraps本身就是一个装饰器,它能把原函数的元信息拷贝到装饰器函数中,使得装饰器函数也有和原函数一样的元信息。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

# 导入functools模块中的wraps装饰器

from functools import wraps

def logged(func):

@wraps(func)

def with_logging(*args,**kwagrs):

print func.__name__+"was called"

return func(*args,**kwargs)

return with_logging

 

@logged

def f(x):

"""does some math"""

return x+x*x

print f.__name__  # print 'f'

print f.__doc__   # print 'does some math'


内置装饰器

在Python中有三个内置的装饰器,都与class相关:

1)staticmethod:类静态方法,其根跟成员方法的区别是没有self参数,并且可以在类不进行实例化的情况下调用。

2)claSSMethod:与成员方法的区别在于所接收的第一个参数不是self(类实例的指针),而是cls(当前类的具体类型)。

3)property:属性的意思,表示可以通过类实例直接访问的信息。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

class Test(object):

def __init__(self,name):

self._name = name

 

@staticmethod

def newTest1(name):

return Test(name)

 

@classmethod

def newTest2(cls):

return Test('')

 

@property

def name(self):

return self._name


装饰器的调用顺序

装饰器是可以叠加使用的,那么这就涉及到装饰器的调用顺序。对于Python中的“@”语法糖,装饰器的调用顺序与使用@语法糖的声明顺序相反。

1

2

3

4

5

6

7

8

9

# 装饰器的声明顺序

 

@a

@b

@c

def f():

    pass

# 等效于

f = a(b(c(f)))    # 以c、b、a的顺序调用

本文出自Http://www.1024do.com/?p=5370

--结束END--

本文标题: python 装饰器理解

本文链接: https://www.lsjlt.com/news/189875.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • python 装饰器理解
    在理解装饰器之前,先应该对闭包有个概念:所谓闭包,就是将组成函数的语句和这些语句的执行环境打包在一起时得到的对象,它的主要作用是封存上下文。这一特性可以巧妙的被用于现有函数的包装,从而为现有函数添加功能,这就是装饰器。装饰器的本质与作用装饰...
    99+
    2023-01-31
    python
  • 理解Python装饰器(一)
    python装饰器 装饰器是什么?我也不知道该如何给装饰器下定义。 1. 装饰器是函数,因为从代码的层面上来说,它就是开发人员定义的一个函数而已; 2. 装饰器就像是类的继承一样,通过装饰符,来实现函数与函数、函数与类之间的"继承" 3. ...
    99+
    2023-01-31
    Python
  • python装饰器1:函数装饰器详解
    装饰器1:函数装饰器 装饰器2:类装饰器 装饰器3:进阶 先混个眼熟 谁可以作为装饰器(可以将谁编写成装饰器): 函数 方法 实现了__call__的可调用类 装饰器可以去装饰谁(谁可以被装饰): 函数 方法 类 基础...
    99+
    2023-01-30
    详解 函数 python
  • Python 装饰器工作原理解析
    #!/usr/bin/env python #coding:utf-8 """ 装饰器实例拆解 """ def login00(func):     print('00请通过验证用户!')     return func def ...
    99+
    2023-01-31
    工作原理 Python
  • python装饰器详解
            python中的装饰器(decorator)一般采用语法糖的形式,是一种语法格式。比如:@classmethod,@staticmethod,@property,@xxx.setter,@wraps(),@func_na...
    99+
    2023-09-01
    python
  • 理解python中装饰器的作用
    装饰器的作用就是用一个新函数封装旧函数(是旧函数代码不变的情况下增加功能)然后会返回一个新函数,新函数就叫做装饰器,一般为了简化装饰器会用语法糖@新函数来简化 例子: 这是一段代码,...
    99+
    2024-04-02
  • python文章装饰器理解12步
    1. 函数 在python中,函数通过def关键字、函数名和可选的参数列表定义。通过return关键字返回值。我们举例来说明如何定义和调用一个简单的函数:   def foo(): return 1 foo() 1 方法体(...
    99+
    2023-01-30
    文章 python
  • python装饰器底层原理详解
    目录1 python装饰器的作用2 python装饰器的原理3 python装饰器的实现3.1 最简陋的装饰器3.2 给有返回值的函数加上装饰器3.3 给有返回值和参数的函数加上装饰...
    99+
    2024-04-02
  • python之我对装饰器的理解
      从一开始学习python的时候,就一直不是很理解装饰器是个什么东东,再看了很多篇博文和自己动手敲了好多代码后,算是略有了解。  我理解的装饰器是: 在不改变原有函数调用的情况下,对其进行包装,使其变成另外一种函数来使用,一般的用途是 插...
    99+
    2023-01-31
    我对 python
  • python装饰器2:类装饰器
    装饰器1:函数装饰器 装饰器2:类装饰器 装饰器3:进阶 本文是装饰器相关内容的第二篇,关于类装饰器。 "类装饰器"有两种解读方式:用来装饰类的装饰器;类作为装饰器装饰其它东西。你如何认为取决于你,两种说法都有出现在其它的文章中。我的...
    99+
    2023-01-30
    python
  • python装饰器
    什么是装饰器:   装饰器就是python中的一个语法糖。作用就是在不改动之前代码的情况下给某个函数增加相应想要增加的功能。 假设需求:   我在几个函数内分别放了一部电影,代码如下: 1 def mv1(): 2 print(...
    99+
    2023-01-30
    python
  • python-装饰器
    装饰器简介:给被装饰的函数在不更改代码的基础上增加新的功能;多个装饰器的执行顺序:从最靠近原始函数的装饰器开始执行,最后执行原始函数; 直接上个简单的例子就懂了: 一 最简单的装饰器:#!/usr/bin/python def deco(f...
    99+
    2023-01-31
    python
  • python 装饰器
    装饰器本质上是一个Python函数,它可以让其他函数在不雲要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面雲求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳...
    99+
    2023-01-30
    python
  • python中装饰器的原理
    装饰器这玩意挺有用,当时感觉各种绕,现在终于绕明白了,俺滴个大爷,还是要慢慢思考才能买明白各种的真谛,没事就来绕一绕   def outer(func): def inner(): print("认证成功") ...
    99+
    2023-01-30
    原理 python
  • Python学习之装饰器与类的装饰器详解
    目录装饰器装饰器的定义装饰器的用法类中的装饰器类的装饰器 - classmethod类的装饰器 - staticmethod类的装饰器 - property通过学习装饰器可以让我们更...
    99+
    2024-04-02
  • python 装饰器案例解析
    本文介绍几个装饰器案例,来分析装饰器是如何调用的获取函数运行时间的例子写装饰器,不可以一步到位,要慢慢一点一点的来先写好2个函数import time def test1():    &nb...
    99+
    2023-01-30
    案例 python
  • python装饰器代码解析
    目录1.装饰器通用模型2.多个装饰器装饰的函数执行3.带参数的装饰器4.类装饰器1.装饰器通用模型 def wrapper(fn):     def inner(*args, **k...
    99+
    2024-04-02
  • Python中装饰器的基本功能理解
    目录前言什么是装饰器Python 函数的基本特性函数名的本质:将函数作为变量使用:进一步实现装饰器使用Python装饰器语句:总结前言 在 python 中,装饰器由于是 pytho...
    99+
    2024-04-02
  • 对Python装饰器的个人理解方法
    0.说明                 在自己好好总结并对Python装饰器的执行过程进行分解之前,对于装饰器虽然理解它的基本工作方式,但对于存在复杂参数的装饰器(装饰器和函数本身都有参数),总是会感到很模糊,即使这会弄懂了,下一次也很快...
    99+
    2023-01-31
    方法 Python
  • Python Pytest装饰器@pytest.mark.parametrize详解
    Pytest中装饰器@pytest.mark.parametrize('参数名',list)可以实现测试用例参数化,类似DDT 如:@pytest.mark.parametrize(...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作