Python 具有强大的功能和富有表现力的语法。我最喜欢的装饰之一。在设计模式的上下文中,装饰器动态更改方法或类功能,而不必直接使用子类。当您需要扩展功能,但不想修改原函数时,这是理想的选择。我们可以在任何地方实现装饰器模式,但是 Python 通过提供更具表现力的功能和语法来促进实现。

在这篇文章中,将讨论 Python 的函数装饰器,并附带一些澄清有关概念的示例。所有示例均适用 Python 2.7,但相同的概念应适用于Python 3,但语法有所更改。

本质上,装饰器充当包装器,在目标函数执行之前和之后修改代码的行为,而无需修改函数本身,从而增强了原始功能,从而对其进行了装饰。

您需要了解的功能

在潜水之前,应先弄清一些先决条件。在 Python 中,函数是一等公民,它们是对象,这意味着我们可以用它们做很多有用的事情。

将函数分配给变量

1

2

3

4

5

6

7

def greet(name):

return "hello "+name

greet_someone = greet

print(greet_someone("John"))

# 输出: hello John

在其他函数中定义函数

1

2

3

4

5

6

7

8

9

10

def greet(name):

def get_message():

return "Hello "

result = get_message()+name

return result

print(greet("John"))

# 输出: Hello John

可以将函数作为参数传递给其他函数

1

2

3

4

5

6

7

8

9

10

def greet(name):

return "Hello " + name

def call_func(func):

other_name = "John"

return func(other_name)

print(call_func(greet))

# 输出: Hello John

函数可以返回其他函数

换句话说, 函数生成其他函数。

1

2

3

4

5

6

7

8

9

10

def compose_greet_func():

def get_message():

return "Hello there!"

return get_message

greet = compose_greet_func()

print(greet())

# 输出: Hello there!

内部函数可以访问封闭范围

更通常称为闭包。在构建装饰器时会遇到的一种非常强大的模式。还要注意的另一件事是,Python 只允许对外部作用域进行读取访问,而不是赋值。请注意,我们如何修改上面的示例以从内部函数的封闭范围中读取“name” 参数并返回新函数。

1

2

3

4

5

6

7

8

9

10

def compose_greet_func(name):

def get_message():

return "Hello there "+name+"!"

return get_message

greet = compose_greet_func("John")

print(greet())

# 输出: Hello there John!

装饰者的组成

函数装饰器只是现有函数的包装器。综上所述,我们可以构建一个装饰器。在此示例中,我们考虑一个函数,该函数通过p标签包装另一个函数的字符串输出。

1

2

3

4

5

6

7

8

9

10

11

12

13

def get_text(name):

return "lorem ipsum, {0} dolor sit amet".format(name)

def p_decorate(func):

def func_wrapper(name):

return "

{0}

".format(func(name))

return func_wrapper

my_get_text = p_decorate(get_text)

print(my_get_text("John"))

# 输出:

lorem ipsum, John dolor sit amet

那是我们的第一个装饰。一个将另一个函数作为参数的函数,将生成一个新函数,以扩展原始函数的功能,并返回生成的函数,以便我们可以在任何地方使用它。要让 get_text 本身由 p_decorate 装饰,我们只需将 p_decorate 的结果再赋值给 get_text 即可。

1

2

3

4

5

get_text = p_decorate(get_text)

print(get_text("John"))

# 输出:

lorem ipsum, John dolor sit amet

还要注意的另一点是,我们的修饰函数带有一个 name 参数。在装饰器中我们要做的就是让 get_text 的包装传递该参数。

Python的装饰语法

Python通过一些语法糖使创建和使用装饰器对程序员来说更干净,更友好。不必装饰 get_text,get_text = p_decorator(get_text) 它有一个捷径,即在要使用的函数之前提供装饰函数的名称即可。装饰器的名称应带有@符号。

1

2

3

4

5

6

7

8

9

10

11

12

def p_decorate(func):

def func_wrapper(name):

return "

{0}

".format(func(name))

return func_wrapper

@p_decorate

def get_text(name):

return "lorem ipsum, {0} dolor sit amet".format(name)

print(get_text("John"))

# 输出:

lorem ipsum, John dolor sit amet

现在,让我们考虑我们要用其他2个函数来修饰 get_text 函数,以便在字符串输出周围包装div和strong标签。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

def p_decorate(func):

def func_wrapper(name):

return "

{0}

".format(func(name))

return func_wrapper

def strong_decorate(func):

def func_wrapper(name):

return "{0}".format(func(name))

return func_wrapper

def div_decorate(func):

def func_wrapper(name):

return "

{0}

".format(func(name))

return func_wrapper

使用基本方法,装饰 get_text 将遵循以下步骤:

1

get_text = div_decorate(p_decorate(strong_decorate(get_text)))

使用 Python 的装饰器语法,可以用更具表达力的功能实现相同功能。

1

2

3

4

5

6

7

8

9

@div_decorate

@p_decorate

@strong_decorate

def get_text(name):

return "lorem ipsum, {0} dolor sit amet".format(name)

print(get_text("John"))

# 输出:

lorem ipsum, John dolor sit amet

这里要注意的一件事是设置装饰器的顺序很重要。如果以上示例中的顺序不同,则输出将不同。

装饰方式

在 Python 中,方法是期望其第一个参数成为对当前对象的引用的函数。我们可以以相同的方式为方法构建装饰器,同时在包装函数中考虑自身。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

def p_decorate(func):

def func_wrapper(self):

return "

{0}

".format(func(self))

return func_wrapper

class Person(object):

def __init__(self):

self.name = "John"

self.family = "Doe"

@p_decorate

def get_fullname(self):

return self.name+" "+self.family

my_person = Person()

print(my_person.get_fullname())

更好的方法是使装饰器对函数和方法都有用。这可以通过将*args 和 **kwargs作为包装器的参数来完成,然后它可以接受任意数量的参数和关键字参数。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

def p_decorate(func):

def func_wrapper(*args, **kwargs):

return "

{0}

".format(func(*args, **kwargs))

return func_wrapper

class Person(object):

def __init__(self):

self.name = "John"

self.family = "Doe"

@p_decorate

def get_fullname(self):

return self.name+" "+self.family

my_person = Person()

print(my_person.get_fullname())

将参数传递给装饰器

回顾上面的示例之前的示例,您会注意到示例中的装饰器是多么冗余。3个装饰器(div_decorate,p_decorate,strong_decorate)具有相同的功能,但用不同的标签包装字符串。我们绝对可以做得更好。为什么不为将标签包装为字符串的标签提供更通用的实现?是的,请!

1

2

3

4

5

6

7

8

9

10

11

12

13

14

def tags(tag_name):

def tags_decorator(func):

def func_wrapper(name):

return "<{0}>{1}{0}>".format(tag_name, func(name))

return func_wrapper

return tags_decorator

@tags("p")

def get_text(name):

return "Hello "+name

print(get_text("John"))

# 输出

Hello John

在这种情况下,需要做更多的工作。装饰器期望接收一个函数作为参数,这就是为什么我们必须构建一个接受这些额外参数并动态生成装饰器的原因。在上面的示例tags,是我们的装饰器生成器。

调试装饰功能

归根结底,装饰器只是包装我们的函数,以防调试出现问题,因为包装器函数不携带原始函数的名称,模块和文档字符串。基于上面的示例,如果我们这样做:

1

2

print(get_text.__name__)

# 输出 func_wrapper

期待输出get_text,然而,get_text的__name__,__doc__和__module__属性被包装(func_wrapper)覆盖。显然,我们可以在func_wrapper中重置它们,但是Python提供了一种更好的方法。

救援工具

幸运的是,Python(从版本2.5开始)包括functools模块,其中包含functools.wraps。Wraps 是一个修饰器,用于将包装函数(func_wrapper)的属性更新为原始函数(get_text)的属性。这就像通过@wraps(func)装饰func_wrapper一样简单。这是更新的示例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

from functools import wraps

def tags(tag_name):

def tags_decorator(func):

@wraps(func)

def func_wrapper(name):

return "<{0}>{1}{0}>".format(tag_name, func(name))

return func_wrapper

return tags_decorator

@tags("p")

def get_text(name):

"""returns some text"""

return "Hello "+name

print(get_text.__name__) # get_text

print(get_text.__doc__) # returns some text

print(get_text.__module__) # __main__

您可以从输出中注意到,get_text 的属性现在是正确的属性。

装饰器在哪里使用

相对于您可以使用装饰器完成的工作量,本文中的示例非常简单。它们可以为您的程序提供如此强大的功能。通常,装饰器是扩展我们不想修改的函数的行为的理想选择。有关有用的装饰器的大量清单,建议您查看Python Decorator Library

python函数修饰器_Python函数装饰器指南相关推荐

  1. python闭包函数使用教程_Python闭包装饰器使用方法汇总

    闭包内容: 匿名函数:能够完成简单的功能,传递这个函数的引用,只有功能 普通函数:能够完成复杂的功能,传递这个函数的引用,只有功能 闭包:能够完成较为复杂的功能,传递这个闭包中的函数以及数据,因此传递 ...

  2. python装饰器_Python基础-装饰器

    作者:Zarten知乎专栏:Python基础深入详解知乎ID: Zarten简介: 互联网一线工作者,尊重原创并欢迎评论留言指出不足之处,也希望多些关注和点赞是给作者最好的鼓励 ! 概述 装饰器其实就 ...

  3. python基础装饰器_Python基础 装饰器及练习

    Python视频教程讲解装饰器 推荐免费:Python视频教程 装饰器概念 装饰器,说白了,就是用来装饰函数的一个函数. 装饰器遵循 开放封闭原则.依赖倒置原则,这两个原则概念,自行百度下, 装饰器长 ...

  4. python3层装饰器_python三层装饰器python字符串,数值计算

    Python是一种面向对象的语言,但它不像C++一样把标准类都封装到库中,而是进行了进一步的封装,语言本身就集成一些类和函数,比如print,list,dict etc. 给编程带来很大的便捷 Pyt ...

  5. python迭代器的用法_python的装饰器,迭代器用法

    装饰器. 装饰器实际就是一个函数 定义:在不改变内部代码和调用方式的基础上增加新的功能 了解装饰器需要了解3个内容: 1.函数即变量 2.高阶函数 1).把一个函数名当作实参传给另一个函数 2).返回 ...

  6. python 动态添加装饰器_python动态装饰器

    python的装饰器是静态的,也就是说你使用的装饰器一定是定义好的对象.在某些特殊的情况下,需要让动态使用装饰器. 警告 不要随便用这个办法,一点都不优雅,能够使用其他的方法规避动态调用装饰器就不要这 ...

  7. python 类方法装饰器_python类装饰器即__call__方法

    上一篇中我对学习过程中的装饰器进行了总结和整理,这一节简单整理下类装饰器 1.类中的__call__方法: 我们在定义好一个类后,实例化出一个对象,如果对这个对象以直接在后边加括号的方式进行调用,程序 ...

  8. python反射、闭包、装饰器_python 闭包装饰器(一)

    一.闭包 1.举例 defouter(): x= 10 def inner(): #内部函数 print(x) #外部函数的一个变量 returninner#调用inner()函数的方法 outer( ...

  9. python捕获异常装饰器_python异常装饰器--比较全的版本了

    #异常捕获装饰器(亦可用于类方法) def try_except_log(f=None, max_retries: int = 5, delay: (int, float) = 1, step: (i ...

  10. python文件下载速度 装饰器_python使用装饰器对文件进行读写操作'及遍历文件目录...

    '''使用装饰器对文件进行读写操作''' #def check_permission(func):#'''演示嵌套函数定义及使用'''#def wrapper(*args,**kwargs):#''' ...

最新文章

  1. java robot类自动截屏
  2. java doublebuffer_Java DoubleBuffer clear()用法及代码示例
  3. IP Messenger程序
  4. 378. Kth Smallest Element in a Sorted Matrix 有序矩阵中第K小的元素
  5. 什么样的征信才算是好的?
  6. centos安装mysql5.6系统崩溃_CentOS7安装MySQL5.6冲突总结
  7. ajax php 错误提示,php – jQuery AJAX错误处理
  8. CentOS系统使用yum安装配置MariaDB数据库
  9. python 入门基础-零基础入门Python,看这一篇就够了!
  10. java被安全阻止解决及用友Uclient安装
  11. Java商店管理系统
  12. 家里两台电脑怎么共享文件_家里有两个电脑~怎么连局域网和文件共享
  13. sfu计算机硕士,别告诉我你了解菲莎国际学院
  14. CANopen协议介绍
  15. 动量梯度下降法 Momentum
  16. 计算机网络实验三 cpt
  17. 自然数拆分Lunatic版
  18. vs2008链接错误的解决方法1:fatal error C1047,fatal error LNK1257
  19. redis.clients java_redis报错redis/clients/jedis/JedisPoolConfig'(curren
  20. 蓝牙(BLE)传输数据的吞吐量

热门文章

  1. js创建对象的高级模式
  2. 操作系统-命令解释程序(实验一)
  3. 分区表的本地索引竟然失效了——ORA-01502
  4. 基于BindingSource的WinForm开发
  5. 波卡链Substrate (1)生态介绍
  6. java结丹期(12)----javaweb(servletHTTPweb相关基本概念)
  7. 近世代数--极大理想--I是R的极大理想↔R/I是域
  8. Cryptohack-RSA writeups
  9. MySQL外键关联(一对多)MySQL连接查询
  10. DNS_ARP_DHCP协议