- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Python函数装饰器指南由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
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 "<
p
>{0}</
p
>".format(func(name))
return func_wrapper
my_get_text = p_decorate(get_text)
print(my_get_text("John"))
# 输出: <
p
> lorem ipsum, John dolor sit amet</
p
>
|
那是我们的第一个装饰。一个将另一个函数作为参数的函数,将生成一个新函数,以扩展原始函数的功能,并返回生成的函数,以便我们可以在任何地方使用它。要让 get_text 本身由 p_decorate 装饰,我们只需将 p_decorate 的结果再赋值给 get_text 即可.
1
2
3
4
5
|
get_text = p_decorate(get_text)
print(get_text("John"))
# 输出:<
p
>lorem ipsum, John dolor sit amet</
p
>
|
还要注意的另一点是,我们的修饰函数带有一个 name 参数。在装饰器中我们要做的就是让 get_text 的包装传递该参数.
。
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 "<
p
>{0}</
p
>".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"))
# 输出: <
p
>lorem ipsum, John dolor sit amet</
p
>
|
现在,让我们考虑我们要用其他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 "<
p
>{0}</
p
>".format(func(name))
return func_wrapper
def strong_decorate(func):
def func_wrapper(name):
return "<
strong
>{0}</
strong
>".format(func(name))
return func_wrapper
def div_decorate(func):
def func_wrapper(name):
return "<
div
>{0}</
div
>".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"))
# 输出: <
div
><
p
><
strong
>lorem ipsum, John dolor sit amet</
strong
></
p
></
div
>
|
这里要注意的一件事是设置装饰器的顺序很重要。如果以上示例中的顺序不同,则输出将不同.
。
在 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 "<
p
>{0}</
p
>".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 "<
p
>{0}</
p
>".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"))
# 输出 <
p
>Hello John</
p
>
|
在这种情况下,需要做更多的工作。装饰器期望接收一个函数作为参数,这就是为什么我们必须构建一个接受这些额外参数并动态生成装饰器的原因。在上面的示例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函数装饰器指南的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在处理一组标记为 160 个组的 173k 点。我想通过合并最接近的(到 9 或 10 个组)来减少组/集群的数量。我搜索过 sklearn 或类似的库,但没有成功。 我猜它只是通过 knn 聚类
我有一个扁平数字列表,这些数字逻辑上以 3 为一组,其中每个三元组是 (number, __ignored, flag[0 or 1]),例如: [7,56,1, 8,0,0, 2,0,0, 6,1,
我正在使用 pipenv 来管理我的包。我想编写一个 python 脚本来调用另一个使用不同虚拟环境(VE)的 python 脚本。 如何运行使用 VE1 的 python 脚本 1 并调用另一个 p
假设我有一个文件 script.py 位于 path = "foo/bar/script.py"。我正在寻找一种在 Python 中通过函数 execute_script() 从我的主要 Python
这听起来像是谜语或笑话,但实际上我还没有找到这个问题的答案。 问题到底是什么? 我想运行 2 个脚本。在第一个脚本中,我调用另一个脚本,但我希望它们继续并行,而不是在两个单独的线程中。主要是我不希望第
我有一个带有 python 2.5.5 的软件。我想发送一个命令,该命令将在 python 2.7.5 中启动一个脚本,然后继续执行该脚本。 我试过用 #!python2.7.5 和http://re
我在 python 命令行(使用 python 2.7)中,并尝试运行 Python 脚本。我的操作系统是 Windows 7。我已将我的目录设置为包含我所有脚本的文件夹,使用: os.chdir("
剧透:部分解决(见最后)。 以下是使用 Python 嵌入的代码示例: #include int main(int argc, char** argv) { Py_SetPythonHome
假设我有以下列表,对应于及时的股票价格: prices = [1, 3, 7, 10, 9, 8, 5, 3, 6, 8, 12, 9, 6, 10, 13, 8, 4, 11] 我想确定以下总体上最
所以我试图在选择某个单选按钮时更改此框架的背景。 我的框架位于一个类中,并且单选按钮的功能位于该类之外。 (这样我就可以在所有其他框架上调用它们。) 问题是每当我选择单选按钮时都会出现以下错误: co
我正在尝试将字符串与 python 中的正则表达式进行比较,如下所示, #!/usr/bin/env python3 import re str1 = "Expecting property name
考虑以下原型(prototype) Boost.Python 模块,该模块从单独的 C++ 头文件中引入类“D”。 /* file: a/b.cpp */ BOOST_PYTHON_MODULE(c)
如何编写一个程序来“识别函数调用的行号?” python 检查模块提供了定位行号的选项,但是, def di(): return inspect.currentframe().f_back.f_l
我已经使用 macports 安装了 Python 2.7,并且由于我的 $PATH 变量,这就是我输入 $ python 时得到的变量。然而,virtualenv 默认使用 Python 2.6,除
我只想问如何加快 python 上的 re.search 速度。 我有一个很长的字符串行,长度为 176861(即带有一些符号的字母数字字符),我使用此函数测试了该行以进行研究: def getExe
list1= [u'%app%%General%%Council%', u'%people%', u'%people%%Regional%%Council%%Mandate%', u'%ppp%%Ge
这个问题在这里已经有了答案: Is it Pythonic to use list comprehensions for just side effects? (7 个答案) 关闭 4 个月前。 告
我想用 Python 将两个列表组合成一个列表,方法如下: a = [1,1,1,2,2,2,3,3,3,3] b= ["Sun", "is", "bright", "June","and" ,"Ju
我正在运行带有最新 Boost 发行版 (1.55.0) 的 Mac OS X 10.8.4 (Darwin 12.4.0)。我正在按照说明 here构建包含在我的发行版中的教程 Boost-Pyth
学习 Python,我正在尝试制作一个没有任何第 3 方库的网络抓取工具,这样过程对我来说并没有简化,而且我知道我在做什么。我浏览了一些在线资源,但所有这些都让我对某些事情感到困惑。 html 看起来
我是一名优秀的程序员,十分优秀!