在Python中完全覆盖属性访问的正确方法是什么?
这个幼稚的类试图模拟基本python对象的属性访问在Python中完全覆盖属性访问的正确方法是什么?,python,descriptor,Python,Descriptor,这个幼稚的类试图模拟基本python对象的属性访问dict和cls显式存储属性和类。其效果是,访问实例的.x将返回dict[x],如果失败,则返回cls.x。就像普通物体一样 class Instance(object): __slots__ = ["dict", "cls"] def __getattribute__(self, key): try: return self.dict[key] except KeyErro
dict
和cls
显式存储属性和类。其效果是,访问实例的.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
具有属性。执行Instance.some_property=10
应访问cls
中定义的属性,但将愉快地将some_property
设置为dict
中的属性
然后是将cls
的方法绑定到Instance
的实例的问题,可能还有更多我甚至不知道的问题
要使上述类尽可能接近python对象运行,似乎有很多细节,而且到目前为止,我所阅读的描述符文档还没有明确说明如何使所有内容都正确
我所要求的是实现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
查找类上的属性会在类级别调用其描述符(即没有实例)的错误。将其替换为直接在基的\uuuu dict\uuuu
中查找的方法。您显然已经发现,实例属性的“点访问”并不像看上去那么容易。它如何工作的文档是源代码。你只是要求重新实施。如果您想更改某些内容,请问一个更具体的问题。@Achim您不必使用CPython使用的相同方法,因为它依赖于对Python对象的C级访问。也许看一下的源代码会有所帮助,因为他们已经在(R)Python中实现了真正的Python属性访问。你到底希望用它实现什么?@Achim:除了将属性访问重定向到指定的dict
和cls
之外,我不想做任何改变。因此,为什么这个问题要求如何以标准方式进行@agf:PyPy建议可能是一个很好的开始,谢谢。虽然我仍然在寻找这个问题的答案@卡尔·克内克特尔:之所以要问这样的问题,通常是因为我认为其他人能够以比我研究它所需的更少的努力来回答。如果你想从课外获得假实例dict呢?您在这里没有cls
的实例,因此如果您在类上调用的方法需要在其\uuuu new\uuuu
或\uuuuu init\uuuuu
中进行设置,该怎么办?在实例的末尾调用示例cls.\uuu init\uuuu
,任何人都不应该这样做(需要这样高级的东西)在计算如何添加对内部dict的访问时遇到困难。我个人使用一个工厂,它首先创建一个实例,然后使用提供的类调用\uuuu init\uuu
。