2

这个幼稚的类试图模仿基本 python 对象的属性访问。dictcls显式存储属性和类。效果是访问.x实例将返回dict[x],或者如果失败,则返回cls.x。就像普通物体一样。

class Instance(object):
    __slots__ = ["dict", "cls"]
    def __getattribute__(self, key):
        try:
            return self.dict[key]
        except KeyError:
            return getattr(self.cls, key)
    def __setattr__(self, key, value):
        if key == "__class__":
            self.cls = value
        else:
            self.dict[key] = value

但它远没有那么简单。一个明显的问题是完全无视描述符。想象一下它cls有属性。DoingInstance.some_property = 10应该访问 中定义的属性cls,但会愉快地设置some_property为 中的属性dict

然后是绑定cls到实例的方法的问题Instance,可能还有更多我什至不知道的问题。

似乎有很多细节可以让上述类尽可能接近python对象,而我迄今为止阅读的描述符文档并没有明确说明如何获得,简单地说,一切都是正确的。

我要的是实现完全替代 python 属性访问的参考。也就是说,上面的类,但是正确的。

4

1 回答 1

1

好吧,我需要这个答案,所以我必须进行研究。以下代码涵盖以下内容:

  • 在设置和获取属性时,数据描述符优先。
  • 非数据描述符被正确调用__getattribute__

下面的代码中可能有拼写错误,因为我必须从内部项目中翻译它。而且我不确定它是否 100% 像 python 对象,所以如果有人能发现错误,那就太好了。

_sentinel = object()

def find_classattr(cls, key):
  for base in cls.__mro__: # Using __mro__ for speed.
    try: return base.__dict__[key]
    except KeyError: pass
  return _sentinel

class Instance(object):
  __slots__ = ["dict", "cls"]
  def __init__(self, d, cls):
    object.__setattr__(self, "dict", d)
    object.__setattr__(self, "cls", cls)
  def __getattribute__(self, key):
    d = object.__getattribute__(self, "dict")
    cls = object.__getattribute__(self, "cls")
    if key == "__class__":
      return cls
    # Data descriptors in the class, defined by presence of '__set__',
    # overrides any other kind of attribute access.
    cls_attr = find_classattr(cls, key)
    if hasattr(cls_attr, '__set__'):
      return cls_attr.__get__(self, cls)
    # Next in order of precedence are instance attributes.
    try:
      return d[key]
    except KeyError:
      # Finally class attributes, that may or may not be non-data descriptors.
      if hasattr(cls_attr, "__get__"):
        return cls_attr.__get__(self, cls)
      if cls_attr is not _sentinel:
        return cls_attr

    raise AttributeError("'{}' object has no attribute '{}'".format(
      getattr(cls, '__name__', "?"), key))
  def __setattr__(self, key, value):
    d = object.__getattribute__(self, "dict")
    cls = object.__getattribute__(self, "cls")
    if key == "__class__":
      object.__setattr__(self, "cls", value)
      return

    # Again, data descriptors override instance attributes.
    cls_attr = find_classattr(cls, key)
    if hasattr(cls_attr, '__set__'):
      cls_attr.__set__(self, value)
    else:
      d[key] = value

有趣的是我意识到我在几年前写过完全相同的东西,但是描述符协议太神秘了,我从那以后就忘记了。

编辑:修复了使用getattr在类上查找属性会在类级别调用它的描述符(即没有实例)的错误。将其替换为直接查看__dict__基础的方法。

于 2012-10-04T11:12:00.610 回答