You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python装饰器inputAssert在类构造方法中执行时机异常的原因排查

问题原因与解决方案

咱们先搞清楚为什么输出顺序和你预期的不一样——核心是你混淆了装饰器的执行阶段。

执行顺序拆解

当Python运行你的代码时,执行流程是这样的:

  1. 首先加载模块中的所有顶层代码,包括装饰器的定义、Demo类的定义。
  2. 解析Demo类内部的代码时,遇到@inputAssert(name=str):
    • 先立即调用inputAssert(name=str),返回内层的decorate函数。
    • 接着把__init__方法作为参数传给decorate,执行decorate(func)——这时候你写的print('input assert')就直接执行了!
    • 最后decorate返回wrapper函数,把原来的__init__替换成这个wrapper。
  3. 等类定义完成后,才会执行if __name__ == '__main__':里的代码,这时候实例化Demo对象,才会调用wrapper,进而执行原来的__init__。

所以input assert会在类加载时就输出,而不是等到实例化的时候。

如何达到预期的输出顺序

如果你希望input assert在调用__init__(也就是实例化对象)时才打印,只需要把print('input assert')移到最内层的wrapper函数里就行——因为只有wrapper是在被装饰的函数被调用时才会执行的:

from functools import wraps
from inspect import signature

def inputAssert(*ty_args, **ty_kwargs):
    def decorate(func):
        # 这部分代码在类定义阶段执行(装饰时)
        sig = signature(func)
        bound_types = sig.bind_partial(*ty_args, **ty_kwargs).arguments
        @wraps(func)
        def wrapper(*args, **kwargs):
            print('input assert')  # 移到这里,调用__init__时执行
            bound_values = sig.bind(*args, **kwargs)
            for name, value in bound_values.arguments.items():
                if name in bound_types:
                    if not isinstance(value, bound_types[name]):
                        raise TypeError(
                            'Argument {} must be {}'.format(name, bound_types[name])
                        )
            return func(*args, **kwargs)
        return wrapper
    return decorate

class Demo:
    @inputAssert(name=str)
    def __init__(self, name=''):
        print('base model init')

if __name__ == '__main__':
    print('------ base model init start----')
    d = Demo(name='xx')
    print('------ base model init finish----')

修改后运行,输出就会和你预期的一致:

------ base model init start----
input assert
base model init
------ base model init finish----

额外提醒

装饰器的三层结构各有不同的执行时机:

  • 最外层inputAssert(*ty_args, **ty_kwargs):在你写@inputAssert(...)时立即执行,用来接收装饰器的参数。
  • 中间层decorate(func):在装饰目标函数/方法时执行,用来处理被装饰的函数,生成包装器。
  • 最内层wrapper(*args, **kwargs):每次调用被装饰的函数/方法时执行,这才是真正包裹原函数逻辑的地方。

内容的提问来源于stack exchange,提问作者Qiang Zhang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 05:54:07