我有一个python类Foo,将观察者注册到一个可观察对象。 我有几个从Foo继承的类,并填充了观察者列表,每个观察者都有不同的观察者。
由于与当前设计相关的原因,观察者列表在每个派生类__init__中被显式初始化,并且不能移动到可重写的方法(将从基类__init__中调用)。
结果是我无法在构造函数中调用observable.RegisterObservers(因为尚未填充观察者列表)。
为了确保观察者已注册,我创建了observable作为缓存属性。这样,我可以保证没有人先注册观察者就不会直接访问该字段。
在完成init之后,对my_observable的第一次调用应该已经发生。 问题是在基类init的末尾有一个inspect.getmembers调用。 inspect.getmembers()使用getattr,并由此评估cached_property。
如果某些条件不满足(即我们仍在初始化中),我试图抛出AttributeError,但是我不喜欢这种解决方案,并且如果有人将以其他方式实现派生类,它将失败。 有没有办法告诉检阅跳过缓存的属性? 还可以采用一种可靠的方式来判断(派生类的)init是否已完成。
伪代码:
class Foo(object):
def __init__(self):
self._observers = []
for _, member in inspect.getmembers(self):
# do something with member
continue
@cached_property
def my_observable:
observable = Observable()
observable.RegisterObservers(self._observers)
return observable
class Bar(Foo):
def __init__(self):
super(Bar, self).__init__()
self._observers = [MyObserver()]
答案 0 :(得分:0)
为我的问题找到了解决方案。 它并不能解决inspect.getmembers评估我的缓存属性的问题,但实际上可以以更好的方式解决设计问题。
我将定义一个元类,该类将覆盖调用,并将在该类上调用特定方法。 通过在元类中覆盖 call ,我们可以在返回新实例之前注入该步骤。
所以它看起来像这样:
class MyMetaClass(type):
def __call__(cls, *args, **kwargs):
"""Called when the object is initialized."""
obj = type.__call__(cls, *args, **kwargs)
obj.FinalizeInit()
return obj
class Foo(object):
__metaclass__ = MyMetaClass
def __init__(self):
self._observers = []
for _, member in inspect.getmembers(self):
# do something with member
continue
self._observable = None
def FinalizeInit(self):
self._observable = Observable()
self._observable.RegisterObservers(self._observers)