装饰器是Python最有用,函数最强大的工具之一。这些用于修改函数的行为。装饰器提供了包装其他函数的灵活性,以扩展包装函数的工作,而无需对其进行永久性修改。
它也称为元编程(meta programming),其中一部分程序尝试在编译时更改另一部分程序。
在理解 Decorator 之前,无涯教程需要了解Python的一些重要概念。
Python具有最有趣的函数,即使类在Python中定义的任何变量也被视为对象,所有东西都被视为对象。函数是Python中的一级公民,因为它们可以引用,传递给变量并从其他函数返回。示例如下:
输出:
Hii Hii
在上面的程序中,当运行代码时,两个函数的输出相同。 func2 指函数 func1 并用作函数,需要了解函数的以下概念:
Python提供了在另一个函数中定义函数的函数。这些类型的函数称为内部函数。考虑以下示例:
def func(): print("We are in first function") def func1(): print("This is first child function") def func2(): print(" This is second child function") func1() func2() func()
输出:
We are in first function This is first child function This is second child function
在上面的程序中,子函数的声明方式无关紧要。子函数的执行会影响输出。这些子函数在本地由 func()限制,因此不能单独调用它们。
接受其他函数作为参数的函数也称为高阶函数。考虑以下示例:
def add(x): return x+1 def sub(x): return x-1 def operator(func, x): temp = func(x) return temp print(operator(sub,10)) print(operator(add,20))
输出:
9 21
在上面的程序中,已将 sub()函数和 add()函数作为 operator()函数的参数传递。
一个函数可以返回另一个函数。考虑以下示例:
输出:
Hello
在上述程序中, hi()函数嵌套在 hello()函数内部。每当调用 hi()时,它将返回。
举一个例子来了解参数化装饰器函数:
def divide(x,y): print(x/y) def outer_div(func): def inner(x,y): if(x<y): x,y = y,x return func(x,y) return inner divide1 = outer_div(divide) divide1(2,4)
输出:
2.0
在上面的程序中,无涯教程装饰了 out_div()有点笨重。代替使用上述方法,Python允许通过
def outer_div(func): def inner(x,y): if(x < y): x,y = y,x return func(x,y) return inner # syntax of generator @outer_div def divide(x,y): print(x/y)
输出:
2.0
还可以通过调用该装饰器函数来重用该装饰器。将装饰器制作成可以在许多其他函数中使用的模块。使用以下代码创建名为 mod_decorator.py 文件:
def do_twice(func): def wrapper_do_twice(): func() func() return wrapper_do_twice
可以在其他文件中导入mod_decorator.py。
from decorator import do_twice @do_twice def say_hello(): print("Hello There") say_hello()
输出:
Hello There Hello There
想在函数中传递一些参数。在以下代码中进行操作:
from decorator import do_twice @do_twice def display(name): print(f"Hello {name}") display()
输出:
TypeError: display() missing 1 required positional argument: 'name'
如上所见,该函数不接受参数。运行此代码将引发错误。可以通过在内部包装函数中使用 * args 和 ** kwargs 来解决此错误。修改 decorator.py 如
def do_twice(func): def wrapper_function(*args,**kwargs): func(*args,**kwargs) func(*args,**kwargs) return wrapper_function
现在, wrapper_function()可以接受任意数量的参数并将其传递给函数。
from decorator import do_twice @do_twice def display(name): print(f"Hello {name}") display("Learnfk")
输出:
Hello Learnfk Hello Learnfk
可以控制修饰函数的返回类型。示例如下:
from decorator import do_twice @do_twice def return_greeting(name): print("We are created greeting") return f"Hi {name}" hi_adam = return_greeting("Adam")
输出:
We are created greeting We are created greeting
Python提供了两种装饰类的方法。首先,可以在类中修饰该方法;在Python中有诸如 @ classmethod,@ staticmethod 和 @property 之类的内置修饰符。 @classmethod 和 @staticmethod 定义了类内部未与任何其他类实例连接的方法。 @property通常用于修改类属性的获取器和设置器。
示例1- @property装饰器-通过使用它,可以将类函数用作属性。考虑以下代码:
class Student: def __init__(self,name,grade): self.name = name self.grade = grade @property def display(self): return self.name + " got grade " + self.grade stu = Student("Learnfk","B") print("Name:", stu.name) print("Grade:", stu.grade) print(stu.display)
输出:
Name: Learnfk Grade: B Learnfk got grade B
示例2- @staticmethod装饰器-@staticmethod用于在类中定义静态方法。通过使用类名以及该类的实例来调用它。
class Person: @staticmethod def hello(): print("Hello Peter") per = Person() per.hello() Person.hello()
输出:
Hello Peter Hello Peter
可以通过将多个装饰器彼此叠加使用来使用它们。
在上面的代码中,通过将嵌套的装饰器相互堆叠来使用它们。
链接:https://www.learnfk.comhttps://www.learnfk.com/python3/python-decorator.html
来源:LearnFk无涯教程网
在装饰器中传递参数总是有用的。装饰器可以根据参数的给定值执行多次。
Import functools def repeat(num): #创建和返回包装函数 def decorator_repeat(func): @functools.wraps(func) def wrapper(*args,**kwargs): for _ in range(num): value = func(*args,**kwargs) return value return wrapper return decorator_repeat #在这里,无涯教程将 num 作为重复打印功能的参数传递 @repeat(num=5) def function1(name): print(f"{name}")
输出:
LearnFK LearnFK LearnFK LearnFK LearnFK
在上面的示例中, @repeat 表示可以在另一个函数中调用的函数对象。 @repeat(num = 5)将返回一个充当装饰器的函数。
上面的代码可能看起来很复杂,但这是最常用的装饰器模式,其中无涯教程使用了另外一个 def 来处理装饰器的参数。
有状态的装饰器用于跟踪装饰器的状态。考虑一个示例,在该示例中,创建一个装饰器,该装饰器计算函数被调用的次数。
Import functools def count_function(func): @functools.wraps(func) def wrapper_count_calls(*args, **kwargs): wrapper_count_calls.num_calls += 1 print(f"Call{wrapper_count_calls.num_calls} of {func.__name__!r}") return func(*args, **kwargs) wrapper_count_calls.num_calls = 0 return wrapper_count_calls @count_function def say_hello(): print("Say Hello") say_hello() say_hello()
输出:
Call 1 of 'say_hello' Say Hello Call 2 of 'say_hello' Say Hello
在上述程序中,状态表示包装函数中存储在 .num_calls 中的函数的调用次数。当调用 say_hello()时,它将显示该函数的调用号。
类是维护状态的最佳方法。在本节中将学习如何使用类作为装饰器。在这里,将创建一个包含 __ init __()的类,并以 func 作为参数。该类必须是可调用的,以便它可以代表修饰的函数。
为了使一个类可调用,实现了特殊的 __ call __()方法。
import functools class Count_Calls: def __init__(self, func): functools.update_wrapper(self, func) self.func = func self.num_calls = 0 def __call__(self, *args, **kwargs): self.num_calls += 1 print(f"Call{self.num_calls} of {self.func.__name__!r}") return self.func(*args, **kwargs) @Count_Calls def say_hello(): print("Say Hello") say_hello() say_hello() say_hello()
输出:
Call 1 of 'say_hello' Say Hello Call 2 of 'say_hello' Say Hello Call 3 of 'say_hello' Say Hello
__ init __()方法存储对该函数的引用,并且可以执行任何其他所需的初始化。
祝学习愉快!(内容编辑有误?请选中要编辑内容 -> 右键 -> 修改 -> 提交!)