那麼,我需要這個答案,所以我不得不做這項研究。以下代碼涵蓋以下內容:
- 數據描述符在設置和獲取屬性時都具有優先權。
- 非數據描述符正確稱爲
__getattribute__
有可能低於我不得不從內部項目轉換代碼錯別字。我不確定它是否像python對象一樣是100%,所以如果任何人都可以發現很棒的錯誤。
_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
找到該類的某個屬性時,會在類級調用它的描述符(即沒有該實例)的bug。將其替換爲直接在__dict__
中顯示的方法。
你很明顯知道,實例屬性的「點訪問」並不像看起來那麼容易。它是如何工作的文檔是源代碼。你只需要重新實現。如果您想改變某些內容,請提出更具體的問題。 – Achim
@Achim您不一定使用CPython使用的相同方法,因爲它取決於對Python對象的C級訪問。也許查看[PyPy Python實現](http://pypy.org/)的源代碼會很有幫助,因爲它們已經在(R)Python中實現了真正的Python屬性訪問。 – agf
你希望用這個做什麼? –