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

如何装饰__enter__和__exit__实例方法?解决装饰器未生效问题

问题原因

Python的特殊方法(如__enter__、__exit__)是通过类层级的查找机制调用的,而非直接读取实例属性。当执行with语句时,解释器会去实例所属的类(这里是contMgr)中查找这两个方法,而不是使用你绑定到实例mgr上的装饰后方法,所以你的wrapper没有被触发。

解决方案

下面提供几种可行的修复方式:

方案1:在类定义时直接装饰方法

直接在类内部给__enter__和__exit__添加装饰器,这是最直接的方式:

def deco(func):
    def wrapper(*args,**kwargs):
        print("In wrapper")
        result = func(*args, **kwargs)
        return result
    
    return wrapper

class contMgr():
    def __init__(self):
        print("In __init__")

    @deco  # 直接装饰__enter__
    def __enter__(self):
        print("In __enter__")
        return self

    @deco  # 直接装饰__exit__
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("In __exit__")

    def __call__(self, *args, **kwargs):
        print("In __call__")

    def brol():
        print("brol")

@deco
def test():
    print("Blah, blah, blah")

mgr = contMgr()
print("------------------------")
with mgr:
    print("------------------------")
    test()
    print("------------------------")

运行后输出符合预期:

In __init__
------------------------
In wrapper
In __enter__
------------------------
In wrapper
Blah, blah, blah
------------------------
In wrapper
In __exit__

方案2:动态修改类的方法(而非实例)

如果不想修改类定义,也可以在实例化后修改类的对应方法,这样所有实例都会生效:

def deco(func):
    def wrapper(*args,**kwargs):
        print("In wrapper")
        result = func(*args, **kwargs)
        return result
    
    return wrapper

class contMgr():
    def __init__(self):
        print("In __init__")

    def __enter__(self):
        print("In __enter__")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("In __exit__")

    def __call__(self, *args, **kwargs):
        print("In __call__")

    def brol():
        print("brol")

@deco
def test():
    print("Blah, blah, blah")

mgr = contMgr()
# 修改类的__enter__和__exit__方法,而非实例属性
contMgr.__enter__ = deco(contMgr.__enter__)
contMgr.__exit__ = deco(contMgr.__exit__)
print("------------------------")
with mgr:
    print("------------------------")
    test()
    print("------------------------")

此方案同样能得到预期输出,核心是修改类的属性而非单个实例。

方案3:使用类装饰器

如果需要批量给类的特殊方法加装饰,可使用类装饰器实现:

def deco(func):
    def wrapper(*args,**kwargs):
        print("In wrapper")
        result = func(*args, **kwargs)
        return result
    
    return wrapper

# 类装饰器:给目标类的__enter__和__exit__方法加装饰
def decorate_special_methods(cls):
    cls.__enter__ = deco(cls.__enter__)
    cls.__exit__ = deco(cls.__exit__)
    return cls

@decorate_special_methods
class contMgr():
    def __init__(self):
        print("In __init__")

    def __enter__(self):
        print("In __enter__")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("In __exit__")

    def __call__(self, *args, **kwargs):
        print("In __call__")

    def brol():
        print("brol")

@deco
def test():
    print("Blah, blah, blah")

mgr = contMgr()
print("------------------------")
with mgr:
    print("------------------------")
    test()
    print("------------------------")

这种方式更灵活,适合需要给多个类的特殊方法统一加装饰的场景。

内容的提问来源于stack exchange,提问作者Walther Hautermann

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 12:03:23