如何跳过inspect.getmembers中的缓存属性

时间:2018-08-01 03:47:18

标签: python

我有一个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()]

1 个答案:

答案 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)