Python装饰器

Python装饰器

装饰器是Python中最有帮助和强大的工具之一。它们用于修改函数的行为。装饰器提供了灵活性,可以包装另一个函数以扩展包装函数的工作,而不会永久修改它。

在装饰器中,函数作为参数传递到另一个函数中,然后在包装器函数内部调用。

它也被称为 元编程 ,即程序的一部分试图在编译时更改另一部分程序。

在理解 装饰器 之前,我们需要了解Python的一些重要概念。

Python中的函数是什么

Python具有最有趣的特性,即一切都被视为对象,甚至是类或我们在Python中定义的任何变量也被视为对象。函数是Python中的 一等公民 对象,因为它们可以引用、传递给变量并从其他函数返回。例如:

示例:

def func1(msg):    # here, we are creating a function and passing the parameter
    print(msg)  
func1("Hii, welcome to function ")   # Here, we are printing the data of function 1
func2 = func1      # Here, we are copying the function 1 data to function 2
func2("Hii, welcome to function ")   # Here, we are printing the data of function 2

输出:

Hii, welcome to function 
Hii, welcome to function 

在上述程序中,当我们运行代码时,两个函数的输出都相同。 func2 引用函数 func1 并充当函数的角色。我们需要了解以下函数的概念:

  • 函数可以被引用,并且可以作为变量传递和从其他函数返回。
  • 函数可以在另一个函数中声明,并作为参数传递给另一个函数。

内部函数

Python提供了在另一个函数内定义函数的功能。这些类型的函数被称为内部函数。考虑以下示例:

示例:

def func():    # here, we are creating a function and passing the parameter
     print("We are in first function")      # Here, we are printing the data of function 
     def func1():      # here, we are creating a function and passing the parameter
           print("This is first child function")  # Here, we are printing the data of function 1 
     def func2():      # here, we are creating a function and passing the parameter
           print("This is second child function")      # Here, we are printing the data of         # function 2 
     func1()  
     func2()  
func()  

输出:

We are in first function
This is first child function
This is second child function

在上面的程序中,子函数的声明方式并不重要。子函数的执行会对输出产生影响。这些子函数与 func() 局部绑定,因此不能被单独调用。

接受其他函数作为参数的函数也被称为 高阶函数 。考虑以下示例:

示例:

def add(x):          # here, we are creating a function add and passing the parameter
    return x+1       # here, we are returning the passed value by adding 1
def sub(x):          # here, we are creating a function sub and passing the parameter
    return x-1        # here, we are returning the passed value by subtracting 1
def operator(func, x):    # here, we are creating a function and passing the parameter
    temp = func(x)  
    return temp  
print(operator(sub,10))  # here, we are printing the operation subtraction with 10
print(operator(add,20))   # here, we are printing the operation addition with 20

输出:

9
21

在上面的程序中,我们将 sub() 函数和 add() 函数作为参数传递给 operator() 函数。

一个函数可以返回另一个函数。考虑下面的示例:

示例:

def hello():         # here, we are creating a function named hello
    def hi():         # here, we are creating a function named hi
        print("Hello")             # here, we are printing the output of the function
    return hi         # here, we are returning the output of the function
new = hello()  
new()  

输出:

Hello

在上面的程序中, hi() 函数嵌套在 hello() 函数内部。每次调用 hi() 时,它都会返回。

使用参数装饰函数

让我们举一个示例来理解带参数的装饰函数:

示例:

def divide(x,y):       # here, we are creating a function and passing the parameter
    print(x/y)         # Here, we are printing the result of the expression
def outer_div(func):      # here, we are creating a function and passing the parameter  
    def inner(x,y):      # here, we are creating a function and passing the parameter
if(x

输出:

2.0

语法修饰器

在上面的程序中,我们装饰了 out_div() 这个有点臃肿的函数。Python允许使用装饰器的简便方法,使用 @符号 。有时候也被称为”pie”语法。

def outer_div(func):     # here, we are creating a function and passing the parameter
    def inner(x,y):        # here, we are creating a function and passing the parameter
if(x

输出:

2.0

重复使用装饰器

我们也可以通过调用装饰器函数来重复使用装饰器。让我们将装饰器制作成一个独立的模块,可以在许多其他函数中使用。创建一个名为 mod_decorator.py 的文件,代码如下:

def do_twice(func):      # here, we are creating a function and passing the parameter
    def wrapper_do_twice():     
     # here, we are creating a function and passing the parameter
        func()  
        func()  
    return wrapper_do_twice  
We can import mod_decorator.py in another file.
from decorator import do_twice  
@do_twice  
def say_hello():  
    print("Hello There")  
say_hello()  

我们可以在其他文件中导入mod_decorator.py。

from decorator import do_twice
@do_twice
def say_hello():
    print("Hello There")
say_hello()

输出:

Hello There
Hello There

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** 来修复这个错误。修改 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("John")

输出:

Hello John
Hello 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定义了与类的任何其他实例无关的类内方法。@property通常用于修改类属性的getter和setter。我们通过以下示例来理解它:

示例:1-

@property装饰器 - 使用它,我们可以将类函数作为属性使用。考虑以下代码:

class Student:     # here, we are creating a class with the name 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 of the student: ", stu.name)  
print("Grade of the student: ", stu.grade)  
print(stu.display)  

输出:

Name of the student: John
Grade of the student: B
John got grade B

示例:2-

@staticmethod装饰器 - @staticmethod用于在类中定义静态方法。它可以通过使用类名以及类的实例来调用。考虑以下代码:

class Person:       # here, we are creating a class with the name Student
     @staticmethod  
     def hello():         # here, we are defining a function hello
          print("Hello Peter")  
per = Person()  
per.hello()  
Person.hello()  

输出:

Hello Peter
Hello Peter

单例类

单例类只有一个实例。Python中有许多单例类,包括True、None等。

嵌套装饰器

我们可以通过将装饰器叠加在一起来使用多个装饰器。让我们看下面的示例:

@function1
@function2
def function(name):
      print(f "{name}")

在上面的代码中,我们使用了嵌套装饰器,将它们叠加在一起。

带有参数的装饰器

在装饰器中传递参数总是很有用的。根据参数的给定值,可以多次执行装饰器。让我们考虑以下示例:

示例:

Import functools      # here, we are importing the functools into our program
def repeat(num):     # here, we are defining a function repeat and passing parameter
# Here, we are creating and returning a wrapper function  
    def decorator_repeat(func):  
        @functools.wraps(func)  
        def wrapper(*args,**kwargs):  
            for _ in range(num):  # here, we are initializing a for loop and iterating till num
                value = func(*args,**kwargs)  
             return value      # here, we are returning the value
          return wrapper    # here, we are returning the wrapper class
    return decorator_repeat  
#Here we are passing num as an argument which repeats the print function  
@repeat(num=5)     
def function1(name):  
     print(f"{name}")  

输出:

JavatPoint
JavatPoint
JavatPoint
JavatPoint
JavatPoint

在上面的示例中, @repeat 是指一个可以在另一个函数中调用的函数对象。 @repeat(num = 5) 会返回一个作为装饰器的函数。

上面的代码可能看起来很复杂,但这是最常用的装饰器模式,我们使用了一个额外的 def 来处理装饰器的参数。

注意:带有参数的装饰器在编程中并不经常使用,但它提供了灵活性。我们可以在使用时带有或不带参数。

有状态的装饰器

有状态的装饰器用于跟踪装饰器的状态。让我们考虑一个示例,我们正在创建一个计算函数被调用次数的装饰器。

示例:

Import functools          # here, we are importing the functools into our program
def count_function(func):     
# here, we are defining a function and passing the parameter 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      # here, we are returning the wrapper call counts
@count_function  
def say_hello():  # here, we are defining a function and passing the parameter 
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         # here, we are importing the functools into our program
class Count_Calls:       # here, we are creating a class for getting the call count
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():  # here, we are defining a function and passing the parameter
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__() 存储函数的引用,并可以进行任何其他所需的初始化。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程