Python进阶知识(二)

文章目录

  • 1.函数装饰器
  • 2.类装饰器
  • 3.装饰器的嵌套
  • 4.装饰器用法实例
    • 4.1 身份认证
    • 4.2 日志记录
    • 4.3 输入合理性检查

1.函数装饰器

Python装饰器是一种用于修改函数或类的行为的特殊语法构造。装饰器允许在不修改原始代码的情况下,通过将函数或类包装在另一个函数中来添加额外的功能。

装饰器通常用于以下场景:

  1. 函数的日志记录:装饰器可以用来记录函数的调用信息,如函数名称、参数和返回值等。这对于调试和性能分析非常有用。
  2. 认证和授权:装饰器可以添加身份验证和授权逻辑,确保只有经过授权的用户才能访问特定的函数或类。
  3. 缓存:装饰器可以用于缓存函数的结果,以避免重复计算相同的输入。
  4. 输入验证和转换:装饰器可以验证函数的输入参数,并在需要时进行转换,确保输入的有效性和一致性。

下面是一个简单的示例,展示如何定义和应用一个装饰器:

def decorator_function(original_function):
    def wrapper_function(*args, **kwargs):
        # 在调用原始函数之前执行的代码
        print("Before the function is called")

        # 调用原始函数
        result = original_function(*args, **kwargs)

        # 在调用原始函数之后执行的代码
        print("After the function is called")

        # 返回结果
        return result

    # 返回包装函数
    return wrapper_function

# 应用装饰器
@decorator_function
def my_function():
    print("Inside the function")

# 调用被装饰的函数
my_function()

输出结果:

sqlCopy code
Before the function is called
Inside the function
After the function is called

在上面的例子中,decorator_function 是一个装饰器函数,它接受一个原始函数作为参数,并返回一个包装函数 wrapper_function。包装函数在调用原始函数之前和之后执行额外的代码,从而实现了函数行为的修改。

装饰器使用 @ 符号应用到目标函数上。在上述例子中,通过 @decorator_function 将装饰器应用到 my_function 上,使得 my_function 在调用前后会执行装饰器中定义的代码。

在装饰器中,def wrapper_function(*args, **kwargs) 定义了一个包装函数,它接受任意数量的位置参数 args 和关键字参数 kwargs。这种形式的参数定义使用了 *** 运算符,允许将不定数量的参数传递给函数。

*args 表示将多个位置参数打包成一个元组(tuple),在函数内部可以通过 args 来访问这个元组。这样,当原始函数被调用时,可以将传递给原始函数的所有位置参数捕获到 args 中,然后在包装函数内部调用原始函数时,再将这些参数传递给原始函数。

类似地,**kwargs 表示将多个关键字参数打包成一个字典(dictionary),在函数内部可以通过 kwargs 来访问这个字典。这样,当原始函数被调用时,可以将传递给原始函数的所有关键字参数捕获到 kwargs 中,然后在包装函数内部调用原始函数时,再将这些参数传递给原始函数。

使用 *args**kwargs 的好处是,装饰器可以适应不同原始函数的参数签名。无论原始函数接受多少个参数或关键字参数,装饰器都能正确地捕获和传递这些参数,使得装饰器对不同函数的适用性更广泛。

在包装函数内部,可以根据需要访问和操作 argskwargs,例如可以对它们进行修改、添加新的参数等。然后,在调用原始函数时,可以使用 *args**kwargs 语法来将捕获的参数传递给原始函数,确保参数的正确传递。

需要注意的是,在定义装饰器时,*args**kwargs 只是约定俗成的名称,并不是固定的。你可以选择其他的名称,但建议使用习惯用法,这样可以增加代码的可读性,让其他开发者更容易理解你的代码意图。

总之,def wrapper_function(*args, **kwargs) 定义了一个接受任意数量位置参数和关键字参数的包装函数,使得装饰器可以适用于不同的函数签名。

2.类装饰器

Python类装饰器是一种装饰器形式,其中装饰器本身是一个类,而不是函数。类装饰器通过实现__call__()方法来使实例对象可调用,从而实现对函数或类的装饰。

下面是一个简单的示例,展示如何定义和应用一个类装饰器:

class DecoratorClass:
    def __init__(self, original_function):
        self.original_function = original_function

    def __call__(self, *args, **kwargs):
        # 在调用原始函数之前执行的代码
        print("Before the function is called")

        # 调用原始函数
        result = self.original_function(*args, **kwargs)

        # 在调用原始函数之后执行的代码
        print("After the function is called")

        # 返回结果
        return result

# 应用装饰器
@DecoratorClass
def my_function():
    print("Inside the function")

# 调用被装饰的函数
my_function()

输出结果:

sqlCopy code
Before the function is called
Inside the function
After the function is called

在上面的例子中,DecoratorClass 是一个类装饰器,它接受一个原始函数作为参数,并在 __init__() 方法中保存该函数的引用。通过实现 __call__() 方法,该类的实例可以被调用,即实现了可调用对象的行为。

__call__() 方法中,类装饰器定义了在调用原始函数之前和之后执行的代码。通过 self.original_function 引用原始函数,并将传递给装饰器的参数 *args**kwargs 传递给原始函数。

装饰器通过 @DecoratorClass 语法应用到目标函数上。在上述例子中,通过 @DecoratorClass 将装饰器应用到 my_function 上,使得 my_function 在调用前后会执行装饰器中定义的代码。

3.装饰器的嵌套

Python装饰器支持嵌套,也就是说一个装饰器可以被另一个装饰器所装饰。通过嵌套装饰器,可以在函数或类上应用多个装饰器,从而按照特定的顺序为其添加不同的功能。

下面是一个示例,展示了如何使用嵌套装饰器:

def decorator1(original_function):
    def wrapper_function(*args, **kwargs):
        print("Decorator 1 - Before the function is called")
        result = original_function(*args, **kwargs)
        print("Decorator 1 - After the function is called")
        return result
    return wrapper_function

def decorator2(original_function):
    def wrapper_function(*args, **kwargs):
        print("Decorator 2 - Before the function is called")
        result = original_function(*args, **kwargs)
        print("Decorator 2 - After the function is called")
        return result
    return wrapper_function

@decorator1
@decorator2
def my_function():
    print("Inside the function")

my_function()

输出结果:

Decorator 1 - Before the function is called
Decorator 2 - Before the function is called
Inside the function
Decorator 2 - After the function is called
Decorator 1 - After the function is called

在上述示例中,decorator1decorator2 是两个装饰器函数。可以看到,它们的定义与之前的例子中的装饰器函数相同。

通过在 my_function 上使用 @decorator1@decorator2,这两个装饰器被嵌套应用到 my_function 上。当调用 my_function 时,装饰器的顺序是从下到上,即先应用 decorator2,再应用 decorator1

装饰器的嵌套顺序非常重要,因为它决定了装饰器的执行顺序。在上述示例中,先执行 decorator2 的代码,然后再执行 decorator1 的代码。这种顺序可以根据实际需求进行调整。

需要注意的是,装饰器的嵌套可以有多层,你可以根据需要在函数或类上应用多个装饰器。每个装饰器都会对目标函数或类进行修改或扩展,从而实现不同的功能。

通过装饰器的嵌套,你可以灵活地组合和应用多个装饰器,以满足特定的需求,并在不修改原始代码的情况下为函数或类添加各种功能。

4.装饰器用法实例

4.1 身份认证

你登录微信,需要输入用户名密码,然后点击确认,这样,服务器端便会查询你的用户名是否存在、是否和密码匹
配等等。如果认证通过,你就可以顺利登录;如果不通过,就抛出异常并提示你登录失败。
再比如一些网站,你不登录也可以浏览内容,但如果你想要发布文章或留言,在点击发布时,
服务器端便会查询你是否登录。如果没有登录,就不允许这项操作等等
import functools
def authenticate(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
      request = args[0]
      if check_user_logged_in(request): # 如果用户处于登录状态
         return func(*args, **kwargs) # 执行函数post_comment()
      else:
         raise Exception('Authentication failed')
    return wrapper
@authenticate
def post_comment(request, ...)
这段代码中,我们定义了装饰器 authenticate;而函数 post_comment(),则表示发表用户 对某篇文章的评论。每次调用这个函数前,都会先检查用户是否处于登录状态,如果是登录状 态,则允许这项操作;如果没有登录,则不允许。
日志记录
日志记录同样是很常见的一个案例。在实际工作中,如果你怀疑某些函数的耗时过长,导致整 个系统的 latency(延迟)增加,所以想在线上测试某些函数的执行时间,那么,装饰器就是 一种很常用的手段。

4.2 日志记录

日志记录同样是很常见的一个案例。在实际工作中,如果你怀疑某些函数的耗时过长,导致整 个系统的 latency(延迟)增加,所以想在线上测试某些函数的执行时间,那么,装饰器就是 一种很常用的手段。

import time
import functools
def log_execution_time(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        res = func(*args, **kwargs)
        end = time.perf_counter()
        print('{} took {} ms'.format(func.__name__, (end - start) * 1000))
        return res
    return wrapper
@log_execution_time
def calculate_similarity(items):

这里,装饰器 log_execution_time 记录某个函数的运行时间,并返回其执行结果。如果你想 计算任何函数的执行时间,在这个函数上方加上@log_execution_time即可。

4.3 输入合理性检查

在大型公司的机器学习框架中,我们调用机器集群进行模型训练前,往往会用装饰器对其输入 (往往是很长的 JSON 文件)进行合理性检查。这样就可以大大避免,输入不正确对机器造 成的巨大开销。

import functools 2
3 def validation_check(input):
4 @functools.wraps(func)
5 def wrapper(*args, **kwargs):
6 ... # 检查输入是否合法
7
8 @validation_check
9 def neural_network_training(param1, param2, ...):

你可能感兴趣的:(人生苦短来玩Python,python,开发语言,算法)