Python函数与装饰器Decorator的原理

本文通过实例来讲述函数与装饰器之间的关系,理解Python编程中装饰器这一概念。Python中,装饰器是针对函数而言的,都是对象,可以接受参数,也可以作为参数传递。装饰器包含另一个函数,扩展了该函数的用法,并返回该函数的值。

Python函数与装饰器Decorator的原理

装饰器避免了代码中不必要的重复,在开发过程中可以预先做一些设置,比如设置计时器、日志处理等;也可以设置有效性和检查运行时。

接下来先看看简单的函数及其调用!

def greet():
    print("小明,你好!")
    
greet_name = greet
greet_name()

输出结果:小明,你好!

从以上代码中可以看出,每项内容都是对象,可以给一个变量赋值,反之,必要的时候可以把函数作为变量的赋值。这一点对理解装饰器很重要!

下面看一个函数作为另一个函数的返回的例子:

def greet():
    def greeting_at_dawn():
        print("早上好!")
        
    return greeting_at_dawn

salute = greet()
salute()

以上代码运行结果:早上好!

在Python编程中,内部函数可以从外部函数中返回,这是函数编程的一个基本概念。

接下来看看函数作为另一个函数的参数进行传递,

def greet_person(func):
    print("你好!", end=' ')
    func()

def say_person():
    print("小明")

greet_person(say_person)

输出结果:你好! 小明

理解以上三个简单的例子,有助于在编程中正确地使用装饰器。

装饰器的工作原理

装饰器是一个函数,那么定义该函数就是定义相应的装饰器,有一个外部打包函数和一个内嵌函数。

一个装饰器的基本编码如下:

def increase_number(func):
    def increase_by_one():
        print("数值按 1 递增 ...")
        number_plus_one = func()  + 1
        return number_plus_one
    return increase_by_one 
    
def get_number():
    return 5
    
get_new_number = increase_number(get_number)
print(get_new_number())

输出结果:

数值按 1 递增 …

6

以上代码中,外部函数increase_number就是装饰器,接收函数func; 打包函数是increase_by_one,其中包含函数get_number;该装饰器increase_number赋值给另一个变量。这就是装饰器的基本语法,但是通常会使用以下更简洁的表示方法:

def increase_number(func):
    def increase_by_one():
        print("数值按 1 递增 ...")
        number_plus_one = func()  + 1
        return number_plus_one
    return increase_by_one 
    
@increase_number    
def get_number():
    return 5

print(get_number())

从以上代码可以看出,装饰器扩展了所需函数参数的功能。

带参数的装饰器

以下代码中,需要把多个参数传递给装饰器:

def multiply_numbers(func):
    def multiply_two_numbers(num1, num2):
        print("两数相乘: {} 和 {}".format(num1, num2))
        return func(num1, num2)
        
    return multiply_two_numbers

@multiply_numbers
def multiply_two_given_numbers(num1, num2):
    return f'{num1} * {num2} = {num1 * num2}'
    
print(multiply_two_given_numbers(3, 4))

运行结果:

两数相乘: 3 和 4

3 * 4 = 12

把多个参数传递给内嵌函数,可以使装饰器用起来更灵活!传递多个参数还可以用以下方法:

def decorator_func(decorated_func):
    def wrapper_func(*args, **kwargs):
        print(f'本函数有 {len(args)} 占位参数和 {len(kwargs)} 关键字参数')
        return decorated_func(*args, **kwargs)
        
    return wrapper_func

@decorator_func
def names_and_age(age1, age2, name1='李冰', name2='王峰'):
    return f'{name1} {age1} 岁, {name2} {age2} 岁'
    
print(names_and_age(12, 15, name1="小明", name2="小倩"))

运行结果:

本函数有 2 占位参数和 2 关键字参数

小明 12 岁, 小倩 15 岁

以上代码中,*args 构成了一个元组,用于迭代占位参数 ,而**kwargs 构成了一个关键字的词典。

多个装饰器并用

在编程中针对某个函数,可以同时并用多个装饰器,看以下代码实例:

def increase_decorator(func):
    def increase_by_two():
        print('数值按 2 递增')
        new_number = func()
        return new_number + 2
        
    return increase_by_two
    

def decrease_decorator(func):
    def decrease_by_one():
        print('数值按 1 递减')
        new_number = func()
        return new_number - 1
        
    return decrease_by_one
    
@increase_decorator
@decrease_decorator
def get_number():
    return 5
    
print(get_number())

运行结果:

数值按 2 递增

数值按 1 递减

6

发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/76171
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!

(0)
股市刺客的头像股市刺客
上一篇 2024 年 7 月 11 日
下一篇 2024 年 7 月 11 日

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注