python - Python 装饰器有必要吗?

标签 python decorator

我对装饰器有基本的了解,但到目前为止它们似乎是多余的并且“hacky”,就像 C 宏但用于函数。

An article为了强调装饰器的重要性,给出了装饰器使用的示例:

from myapp.log import logger

def log_order_event(func):
    def wrapper(*args, **kwargs):
        logger.info("Ordering: %s", func.__name__)
        order = func(*args, **kwargs)
        logger.debug("Order result: %s", order.result)
        return order
    return wrapper

@log_order_event
def order_pizza(*toppings):
    # let's get some pizza!

order_pizza(*toppings) # 用法

这不是相当于下面的无装饰器代码吗?

from myapp.log import logger

def log_order_event(func, *args, **kwargs):
    logger.info("Ordering: %s", func.__name__)
    order = func(*args, **kwargs)
    logger.debug("Order result: %s", order.result)
    return order

def order_pizza(*toppings):
    # let's get some pizza!

log_order_event(order_pizza, *toppings) # 用法

事实上,第二个代码片段不是更容易编写吗,因为它是一个函数,而不是一个函数和一个包装函数?使用调用更长,但它们更清楚地表明实际调用的内容。

这纯粹是品味和语法糖的问题,还是我错过了什么?

最佳答案

就行为而言,两个片段是等效的。但是,我使用装饰器版本有两个主要原因:

  1. 可读性:对于代码片段 2,您需要对一个不太相关的方法进行显式函数调用 log_order_event(),其主要目的是记录。其他方法(例如 order_appetizers())可能需要此日志记录功能,因此,您需要为每个此类方法单独调用 log_order_event()。 (从可读性的角度来看)一次性定义一个执行日志记录的包装器,并且您可以在必要时为此类方法调用包装器(作为装饰器)不是更好吗?装饰器是语法糖,但肯定不是黑客。事实上,PEP 318清楚地讨论了装饰器背后的动机,你一定要读一下。
  2. 可扩展性:考虑这样一种情况,您的代码有多个方法(例如 20 个),例如 order_appetizers()order_maincourse()order_desserts() 等等。我们还假设您想在订购任何这些商品之前执行一些预先检查,例如检查配料(披萨)、卡路里(甜点)等。使用装饰器时,只需在每个检查的单独包装类中定义包装函数,将其导入到主代码中并分别装饰所需的方法即可。这样,您的包装器函数就完全隔离,并且主要逻辑保持干净且易于维护。

    @check_toppings
    @log_order_event
    def order_pizza(*toppings):
        # let's get some pizza!
    
    @check_calories
    @log_order_event
    def order_desserts():
        # let's order some desserts!
    ...and so on for 20 more methods
    

    使用无装饰器逻辑,虽然您可以将检查(和日志)方法分离到单独的类中并导入到主逻辑中,但您仍然需要向每个方法添加单独的调用在每个 order 方法中,从代码维护的角度来看,这可能会令人望而生畏,尤其是对于新手来说。

关于python - Python 装饰器有必要吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59493259/

相关文章:

python - Twilio Auth Windows 环境变量

python - 线程的 Java 文件权限

python - 简单移动平均二维数组python

Python装饰器函数调用深度,结构化输出

javascript - Angular 2 eventEmitter 不起作用

Python按开始和结束字符拆分字符串

python - 在python中将平面列表读入多维数组/矩阵

Python装饰器按名称访问参数

Java,Base64 : How to write a Base64OutputStream class using Decorator Pattern

typescript - 自制方法装饰器删除所有元数据,我该如何解决?