首页 > 编程语言 >Python 装饰器入门

Python 装饰器入门

时间:2024-02-17 15:57:07浏览次数:32  
标签:函数 parent whee Python say child 装饰 def 入门

目录

  • Python 函数
  • 头等对象
  • 内部功能
  • 作为返回值的函数
  • Python 中的简单装饰器
  • 结论

Python 函数
为了理解装饰器,您必须首先了解函数如何工作的一些细节。函数有很多方面,但在装饰器的上下文中,函数根据给定的参数返回一个值。下面是一个基本示例:
`>>> def add_one(number):
... return number + 1
...

add_one(2)
3`
一般来说,Python 中的函数也可能有副作用,而不仅仅是将输入转换为输出。print() 函数就是一个例子:它返回 None,同时具有将某些内容输出到控制台的副作用。但是,要理解装饰器,只需将函数视为将给定参数转换为值的工具就足够了。

头等对象
在函数式编程中,您几乎完全使用没有副作用的纯函数。虽然不是一种纯粹的函数式语言,但 Python 支持许多函数式编程概念,包括将函数视为一类对象。

这意味着函数可以传递并用作参数,就像任何其他对象(如 str、int、float、list 等)一样。请考虑以下三个功能:
`def say_hello(name):
return f"Hello {name}"

def be_awesome(name):
return f"Yo {name}, together we're the awesomest!"

def greet_bob(greeter_func):
return greeter_func("Bob")`
这里,和是常规函数,它们需要以字符串形式给出名称。但是,该函数需要一个函数作为其参数。例如,您可以向它传递 或 函数。say_hello()be_awesome()greet_bob()say_hello()be_awesome()

若要测试函数,可以在交互模式下运行代码。你用标志来执行此操作。例如,如果您的代码位于名为 的文件中,则运行:-igreeters.pypython -i greeters.py
`>>> greet_bob(say_hello)
'Hello Bob'

greet_bob(be_awesome)
'Yo Bob, together we're the awesomest!'`
请注意,它指的是两个函数,但方式不同:和 。该函数的命名不带括号。这意味着仅传递对函数的引用。该函数未执行。另一方面,该函数是用括号编写的,因此将像往常一样调用它。greet_bob(say_hello)greet_bob()say_hellosay_hellogreet_bob()

这是一个重要的区别,对于函数如何作为一类对象工作至关重要。不带括号的函数名称是对函数的引用,而带尾部括号的函数名称调用函数并引用其返回值。

内部功能
可以在其他函数中定义函数。这种函数称为内部函数。下面是一个具有两个内部函数的函数示例:
`def parent():
print("Printing from parent()")

def first_child():
    print("Printing from first_child()")

def second_child():
    print("Printing from second_child()")

second_child()
first_child()`

调用函数时会发生什么情况?想一想。然后在交互模式下运行以尝试一下。输出如下:parent()inner_functions.py
>>> parent() Printing from parent() Printing from second_child() Printing from first_child()
请注意,定义内部函数的顺序无关紧要。与任何其他功能一样,打印仅在执行内部功能时发生。

此外,在调用父函数之前,不会定义内部函数。它们的作用域为 ,这意味着它们仅作为局部变量存在于函数内部。尝试调用 。您会收到一个错误:parent()parent()first_child()
每当你调用时,内部函数也被调用。但是,由于它们的本地范围,它们在函数之外不可用。parent()first_child()second_child()parent()

作为返回值的函数
Python 还允许您从函数返回函数。在以下示例中,重写以返回其中一个内部函数:parent()

`def parent(num):
def first_child():
return "Hi, I'm Elias"

def second_child():
    return "Call me Ester"

if num == 1:
    return first_child
else:
    return second_child`

请注意,您返回时没有括号。回想一下,这意味着您正在返回对函数的引用。相反,带括号是指计算函数的结果。您可以在以下示例中看到这一点:first_childfirst_childfirst_child()
`>>> first = parent(1)

second = parent(2)

first
<function parent..first_child at 0x7f599f1e2e18>

second
<function parent..second_child at 0x7f599dad5268>`
有点隐晦的输出意味着该变量引用了 中的局部函数,而指向 。firstfirst_child()parent()secondsecond_child()

现在,即使您无法直接访问它们指向的函数,也可以像使用常规函数一样使用它们:firstsecond
`>>> first()
'Hi, I'm Elias'

second()
'Call me Ester'`
您可以识别在 中定义的内部函数的返回值。parent()

最后,请注意,在前面的示例中,您在父函数中执行了内部函数,例如 .但是,在最后一个示例中,您没有在返回时向内部函数添加括号,例如 。这样,您就可以获得对将来可以调用的每个函数的引用。first_child()first_child

Python 中的简单装饰器
现在您已经了解了函数就像 Python 中的任何其他对象一样,您已经准备好继续前进,看看 Python 装饰器这个神奇的野兽。您将从一个示例开始:
`def decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper

def say_whee():
print("Whee!")

say_whee = decorator(say_whee)`
在这里,您定义了两个正则函数、和 以及一个内部函数。然后,您重新定义以应用于原始 .decorator()say_whee()wrapper()say_whee()decorator()say_whee()

你能猜到当你打电话时会发生什么吗?在 REPL 中尝试一下。除了运行带有标志的文件外,您还可以手动导入函数:say_whee()-i
`>>> from hello_decorator import say_whee

say_whee()
Something is happening before the function is called.
Whee!
Something is happening after the function is called.`
要了解这里发生了什么,请回顾前面的示例。你正在应用你到目前为止所学到的一切。

所谓的装饰发生在以下一行:
say_whee = decorator(say_whee)
实际上,该名称现在指向内部函数。请记住,当您调用以下命令时,您将作为函数返回:say_wheewrapper()wrapperdecorator(say_whee)
>>> say_whee <function decorator.<locals>.wrapper at 0x7f3c5dfd42f0>
但是,它对原始函数的引用为 ,并且它在两次调用之间调用该函数。wrapper()say_whee()funcprint()

简单地说,装饰器包装一个函数,修改其行为。

在继续之前,请看第二个示例。由于是常规的 Python 函数,因此装饰器修改函数的方式可能会动态更改。为了不打扰你的邻居,下面的例子只会在白天运行修饰好的代码:wrapper()
`from datetime import datetime

def not_during_the_night(func):
def wrapper():
if 7 <= datetime.now().hour < 22:
func()
else:
pass # Hush, the neighbors are asleep
return wrapper

def say_whee():
print("Whee!")

say_whee = not_during_the_night(say_whee)如果您尝试在睡前打电话,则不会发生任何事情:say_whee()>>> from quiet_night import say_whee

say_whee()`
此处不打印任何输出。那是因为测试失败了,所以包装器没有调用 ,原来的 .say_whee()iffunc()say_whee()
结论
这是一段相当长的旅程!在本教程中,您首先仔细研究了函数,特别是如何在其他函数中定义它们并像传递任何其他 Python 对象一样传递它们。然后,您了解了装饰器以及如何编写它们
更多详情内容请参阅:Python 装饰器入门

标签:函数,parent,whee,Python,say,child,装饰,def,入门
From: https://www.cnblogs.com/sdfcv/p/18018040

相关文章

  • svg半小时全方位入门
    1-svg应用场景和优势canvas快速入门canvas是HTML5的新特性,它允许我们使用canvas元素在网页上通过JavaScript绘制图像。入门案例:绘制矩形、线段、圆、点<!DOCTYPEhtml><html><head></head><body><!--声明canvas画布宽高为800--><canvasid="c......
  • PID 控制 |(搬运)教程与 python 代码
    因为完全没有自动化和控制基础,所以找了很多博客都没看懂;干货|通俗易懂讲解PID,这是看的最懂的一篇()PID控制的python代码:[TBC]或许可以直接调用的python包:https://github.com/m-lundberg/simple-pid......
  • Python 机器学习 模型保存和加载
    ​ Python机器学习中,模型保存和加载是两个非常重要的操作。模型保存可以将训练好的模型保存到文件,以便以后使用。模型加载可以将保存的文件加载到内存,以便进行预测或评估。最常用保存和加模型的库包括pickle和joblib,另外在使用特定的机器学习库,如scikit-learn、TensorFlow或Py......
  • 关于thrift python接口和java通信出现问题解决
    真的无语,搞了一个下午。使用thrift出现错误,先说一下遇到第一个错误,如下图:那时候代码是这叼样```if__name__=='__main__':handler=MessageServiceHandler()processor=MessageService.Processor(handler)transport=TSocket.TServerSocket(None,"9090"......
  • 算法竞赛经典入门(第2版)习题1
    目前在准备一个竞赛,头绪并不是很清楚,根据知乎的推荐入了一本书《算法竞赛入门经典》(第2版)...下面是写的例题和习题答案也算是简单记录一下学习过程吧。//三位数反转#include<stdio.h>intmain(){intn;scanf("%d",&n);printf("%d%d%d\n",n%10,n/10%10,n/100)......
  • 第 8章 Python 爬虫框架 Scrapy(下)
    第8章Python爬虫框架Scrapy(下)8.1Scrapy对接Selenium有一种反爬虫策略就是通过JS动态加载数据,应对这种策略的两种方法如下:分析Ajax请求,找出请求接口的相关规则,直接去请求接口获取数据。使用Selenium模拟浏览器渲染后抓取页面内容。8.1.1如何对接单独使用Sc......
  • 自适应辛普森法从入门到进门
    前言学数学学的。simpson背景我们要计算这样一个式子:\[\int_l^rf(x)\textdx\]显然计算机是很难把柿子推出来的。函数的拟合对于一个奇怪的函数,为了对其求导,我们可以用一个图像近似且容易求导的函数来替代,这个过程叫做拟合。这里我们用二次函数来替代,那么有:\[\beg......
  • Python 装饰器
    Python装饰器装饰器原理定义本质是函数,用来装饰其他函数,为其他函数添加附加功能原则不能修改被装饰函数的源代码不能修改被装饰的函数的调用方式实现装饰器知识储备函数就是变量高阶函数把一个函数当作实参传给另外一个函数,在不修改被装饰函数源代码情况下为......
  • 数论从入门到进门
    gcd朴素欧几里得(辗转相除法)这一节我们默认:\(a,b\in\mathbb{Z}\)对于求解\(\gcd(a,b)\)需要用朴素欧几里得定理。\[\gcd(a,b)=\gcd(b,a\bmodb)\]gcd\(\gcd\)为\(\text{greatestcommondivisor}\)的缩写,即最大公约数。(或称最大公因数)对于\(\gcd\)函数,有以下......
  • 多项式从入门到进门
    多项式全家福多项式一个以\(x\)为变量的多项式定义在一个代数域\(F\)上,将函数\(A(x)\)表示为形式和:\[A(x)=\sum\limits_{i=0}^{n-1}a_ix^i\]我们称\(a_0,a_1,\cdots,a_n\)为多项式的系数,所有系数都属于数域\(\mathbbF\)。如果一个多项式的最高次的非零系数是\(k......