装饰器是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<y):    
            x,y = y,x    
           return func(x,y)       
# here, we are returning a function with some passed parameters  
     return inner    
divide1 = outer_div(divide)    
divide1(2,4)    

输出:

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<y):    
           x,y = y,x    
          return func(x,y)       # here, we are returning the function with the parameters  
     return inner    
# Here, the below is the syntax of generator    
@outer_div    
def divide(x,y):      # here, we are creating a function and passing the parameter   
     print(x/y)    

输出:

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}")    

输出:

javatiku
javatiku
javatiku
javatiku
javatiku

在上面的示例中,@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()方法存储对函数的引用,并可以进行任何其他所需的初始化。

标签: Tkinter教程, Tkinter安装, Tkinter库, Tkinter入门, Tkinter学习, Tkinter入门教程, Tkinter, Tkinter进阶, Tkinter指南, Tkinter学习指南, Tkinter进阶教程, Tkinter编程