Python 装饰器 装饰器是 Python 最有用和最强大的工具之一。这些用于修改函数的行为。装饰器提供了包装另一个函数的灵活性,以扩展包装函数的工作,而无需永久修改它。
在 Decorators 中,函数作为参数传递给另一个函数,然后在包装函数中调用。
它也被称为meta programming ,程序的一部分试图在编译时改变程序的另一部分。
在理解装饰器 之前,我们需要了解 Python 的一些重要概念。
Python 中有哪些函数? Python 有一个最有趣的特性,那就是所有的东西都被当作一个对象,甚至我们在 Python 中定义的类或者任何变量也被假定为一个对象。函数是 Python 中的第一类对象,因为它们可以引用、传递给变量以及从其他函数返回。示例如下:
def func1 (msg ): print (msg) func1("Hii" ) func2 = func1 func2("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
在上面的程序中,子函数是如何声明的并不重要。子函数的执行会对输出产生影响。这些子函数与**函数()**局部有界,因此不能单独调用。
接受其他函数作为自变量的函数也称为高阶函数 。考虑以下示例:
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 ))
输出:
在上面的程序中,我们已经将 sub() 函数和 add() 函数作为参数传递给了 operator() 函数。
一个函数可以返回另一个函数。考虑下面的例子:
def hello (): def hi (): print ("Hello" ) return hi new = hello() new()
输出:
在上面的程序中, hi() 函数嵌套在 hello() 函数中。每次我们呼叫 hi() 它都会返回。
用参数装饰函数 让我们举一个例子来理解参数化装饰函数:
def divide (x,y ): print (x/y) def outer_div (func ): def inner (x,y ): if (x
输出:
语法装饰器 在上面的程序中,我们已经修饰了 out_div() 有点笨重。Python 不使用上述方法,而是允许用@symbol 轻松使用装饰器。有时它被称为“pie”语法。
def outer_div (func ): def inner (x,y ): if (x
输出:
重用装饰器 我们也可以通过调用装饰函数来重用装饰器。让我们把装饰器做成它自己的模块,可以用在许多其他功能中。使用以下代码创建名为 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()
输出:
带参数的 Python 装饰器 我们想在函数中传递一些参数。让我们用下面的代码来实现:
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 来修复这个错误。如下修改装饰器: *
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("John" )
输出:
从修饰函数返回值 我们可以控制修饰函数的返回类型。示例如下:
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 定义了类内不与类的任何其他实例连接的方法。@属性通常用于修改类属性的 getters 和 setters。让我们通过下面的例子来理解它:
示例:1-@属性装饰器 -通过使用它,我们可以使用类函数作为属性。考虑以下代码:
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("John" ,"B" ) print ("Name:" , stu.name)print ("Grade:" , stu.grade)print (stu.display)
输出:
Name: John Grade: B John got grade B
示例:2-@staticmethod decorator -该@ static method 用于定义类中的一个静态方法。它通过使用类名和类的实例来调用。考虑以下代码:
class Person : @staticmethod def hello (): print ("Hello Peter" ) per = Person() per.hello() Person.hello()
输出:
单例类 单例类只有一个实例。Python 中有很多单例,包括 True、None 等。
嵌套装饰者 我们可以通过将多个装饰器放在一起来使用它们。让我们考虑以下示例:
@function1 @function2 def function (name ): print (f "{name}" )
在上面的代码中,我们通过将嵌套装饰器堆叠在一起来使用它们。
带参数的装饰器 在装饰器中传递参数总是有用的。根据给定的参数值,装饰器可以执行几次。让我们考虑下面的例子:
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 @repeat(num=5 ) def function1 (name ): print (f"{name} " )
输出:
JavatPoint JavatPoint JavatPoint JavatPoint JavatPoint
在上例中, @repeat 指的是可以在另一个函数中调用的函数对象。 @repeat(num = 5) 将返回一个充当装饰器的函数。
上面的代码看起来可能很复杂,但它是最常用的装饰器模式,我们使用了一个额外的 def 来处理装饰器的参数。
注意:带参数的 Decorator 在编程中并不常用,但它提供了灵活性。不管有没有争论,我们都可以使用它。 有状态装饰器 有状态装饰器用于跟踪装饰器状态。让我们考虑这样一个例子,我们正在创建一个装饰器,计算函数被调用的次数。
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 _ 调用包装函数上的 。当我们调用 say_hello() 时,它会显示该函数的调用次数。
装饰类 类是保持状态的最佳方式。在这一节中,我们将学习如何使用类作为装饰器。这里我们将创建一个包含 init () 的类,并将函数 作为参数。该类需要是可调用的,这样它就可以代替修饰函数。
为了使类可调用,我们实现了特殊的 call () 方法。
import functoolsclass 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 () 方法存储对该函数的引用,并且可以进行任何其他所需的初始化。
原文:https://www.javatpoint.com/python-decorator