我想要创建一个contextmanager,它将拦截来自这个类的一个或多个子类的任何对象实例化,并对该对象执行一些操作。
我需要代码,它看起来像这样:
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不是最好的主意,我对任何其他解决方案都是开放的。
发布于 2018-08-15 23:33:47
上下文管理器实际上看不到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__方法,并在上下文管理器退出后返回它.当然,这是不推荐的,因为你基本上是把手指贴在不应该的地方,并且可能会引入难以找到的bug。
除此之外,恐怕做不到。
发布于 2018-08-15 23:25:49
我可以看到,您可以很容易地实现一个稍微不同的上下文管理器:
with my_context_watchdog(some_instance):
pass..。但这可能与检查器函数一样好,而不是您想要的功能。上下文管理器的神奇之处在于__enter__方法,所以这里可能发生的事情太多了,没有任何大规模的重载。可能有一种方法可以让__init__方法
您还可以创建一些构造函数来区分类名,并考虑将其应用于__new__方法:
def new(cls):
if cls.__name__ == 'BaseClass':
pass
# do something
else:
pass
# do a different thinghttps://stackoverflow.com/questions/51867255
复制相似问题