Python上下文管理器和对象创建

时间:2018-08-15 22:22:48

标签: python callback contextmanager

我想创建一个上下文管理器,该上下文管理器将拦截给定类或此类的子类中的任何对象实例,并对该对象执行某些操作。

我sudo代码看起来可能像这样:

with my_context_watchdog(my_callback, BaseClass):
     obj_1 = BaseClass(name) # launch callback
     obj_2 = SubClass(name) # launch callback

     obj_3 = RandomClass(name) # does not launch callback

def my_callback(new_obj):
     print("new object name:", new_obj.name)

反正我可以在Python中做类似的事情吗?

最好是仅在对象完全实例化后 后才执行回调。

重要提示::我无法修改任何对象类,它们在我没有任何控件的库中。我只想在实例化该库的某些类时引发一个回调。

也许contextmanager不是最好的主意,我对任何其他解决方案都持开放态度。

2 个答案:

答案 0 :(得分:2)

上下文管理器实际上在with块中看不到代码。如果您看到一个库在做这样的“魔术”操作,通常在后台某处有一个隐藏的全局变量,并且with块内部调用的函数会与上下文管理器积极配合。

也就是说,您有两个选择。一个有意义,一个非常丑陋。

有意义的一个:

# somewhere in the context manager:
class ContextManagerReturnVal:
    def instantiate(self, cls, *args, **kwargs):
        obj = cls(*args, **kwargs)
        if issubclass(cls, self.base_class):
            self.callback(cls, *args, **kwargs)
        return obj

with watchdog(callback, BaseClass) as instantiate:
    obj1 = instantiate(BaseClass, name)
    obj2 = instantiate(SubClass, name)

丑陋的是猴子在修补BaseClass。您在评论中说,您不能修改 BaseClass-取决于您的意思。如果您无法修改源代码,则仍可以在运行时修改该类,例如:Monkey patching a class in another module in Python 您必须存储原始的__init__方法,并在上下文管理器退出后返回它...当然,不建议这样做,因为您基本上是将手指放在不应该使用的位置,并且可能引入难以理解的方法。查找错误。

除此之外,恐怕无法完成。

答案 1 :(得分:1)

我可以看到您可以轻松实现一个稍微不同的上下文管理器:

with my_context_watchdog(some_instance):
     pass

...但是这可能和检查器功能一样好,而不是您想要的功能。上下文管理器的神奇之处在于__enter__方法,因此在那里可以发生很多事情,而没有任何种类的大规模重载。可能有一种voerride __init__方法

您还可以创建一些可以区分类名称的构造函数,并考虑将其应用于__new__方法:

def new(cls):
     if cls.__name__ == 'BaseClass':
          pass
          # do something
     else:
          pass
          # do a different thing