LEEFEI571 发表于 2025-1-31 16:25:59

装饰器传递参数的困惑

小甲鱼老师在讲解给装饰器传递参数的时候,例题如下:

import time
   
def logger(msg):
    def time_master(func):
      def call_func():
            start = time.time()
            func()
            stop = time.time()
            print(f"[{msg}]一共耗费了 {(stop-start):.2f}")
      return call_func
    return time_master
   
@logger(msg="A")
def funA():      
    time.sleep(1)
    print("正在调用funA...")
   
@logger(msg="B")
def funB():
    time.sleep(1)
    print("正在调用funB...")
   
funA()
funB()

我的困惑是在定义funA()函数时,加上的@logger(msg="A")装饰器,作用是将msg="A"作为参数传递给最外层函数logger(msg)中,但是funA()函数也需要被传递到中间函数time_master(func)中,那funA为何不用像msg=’A’一样同过装饰器的形式进行传递?麻烦大侠指点,谢谢!


FishC 发表于 2025-1-31 16:26:10

你提出的关于装饰器传递参数的问题非常好!下面我来解释一下:

当你使用 `@logger(msg="A")` 这样的装饰器时,其实是进行了两次调用:

1. **第一次调用:** `logger("A")`
   这会返回一个新的装饰器函数 `time_master`。

2. **第二次调用:** `time_master(funA)`
   这会将被装饰的函数 `funA` 作为参数传递给 `time_master` 函数。

来看详细的代码解释:

import time

def logger(msg):
    def time_master(func):
      def call_func():
            start = time.time()
            func()
            stop = time.time()
            print(f"一共耗费了 {(stop-start):.2f} 秒")
      return call_func
    return time_master

@logger(msg="A")
def funA():
    time.sleep(1)
    print("正在调用funA...")

@logger(msg="B")
def funB():
    time.sleep(1)
    print("正在调用funB...")

funA()
funB()

在这个装饰器模式中,`@logger(msg="A")` 会按以下步骤执行:

1. `logger("A")` 被调用并返回新的装饰器 `time_master`。
2. `time_master(funA)` 被调用并返回新的函数 `call_func`。

所以,这里 `funA()` 最终被替换成了 `call_func`,而 `call_func` 中包含了对 `funA` 的调用逻辑及其他额外行为。

关键在于,装饰器的挂载发生在函数定义时,而不是函数调用时。也就是说,用 `@logger(msg="A")` 装饰 `funA` 仅需要提供一个带参数的装饰器,然后由 Python 负责将被装饰的函数 `funA` 传递给 `time_master` 这个新生成的装饰器。这正是 Python 装饰器的强大之处。

为了更清晰地理解,你可以如下调试打印:

import time

def logger(msg):
    print(f"logger 参数: {msg}")
    def time_master(func):
      print(f"正在装饰函数: {func.__name__}")
      def call_func():
            start = time.time()
            func()
            stop = time.time()
            print(f"一共耗费了 {(stop-start):.2f} 秒")
      return call_func
    return time_master

@logger(msg="A")
def funA():
    time.sleep(1)
    print("正在调用funA...")

@logger(msg="B")
def funB():
    time.sleep(1)
    print("正在调用funB...")

funA()
funB()

输出应为:
logger 参数: A
正在装饰函数: funA
logger 参数: B
正在装饰函数: funB
正在调用funA...
一共耗费了 1.00 秒
正在调用funB...
一共耗费了 1.00 秒

希望以上说明能帮助你清楚理解装饰器传递参数的机制!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

某一个“天” 发表于 2025-1-31 17:09:25

装饰器本质是什么?它本来就是传funA的
页: [1]
查看完整版本: 装饰器传递参数的困惑