当然self.__dict__["_a"] 会返回self._a(实际上是相反的——self._a 会返回self.__dict__["_a"] - 但无论如何),而不是self.a。 property 在这里做的唯一一件事就是自动调用它的 getter(你的 a(self) 函数),这样你就不必输入括号,否则它只是一个普通的方法调用。
如果您也想要一些与属性一起使用的东西,则必须从 dir(self.__class__) 和 getattr(self.__class__, name) 手动获取它们,即:
def __str__(self):
# py2
attribs = self.__dict__.items()
# py3
# attribs = list(self.__dict__.items())
for name in dir(self.__class__):
obj = getattr(self.__class__, name)
if isinstance(obj, property):
val = obj.__get__(self, self.__class__)
attribs.append((name, val))
return ' '.join('{}: {}'.format(key, val) for key, val in attribs)
请注意,这不会阻止 _a 出现在 attribs 中 - 如果您想避免这种情况,您还必须从 attribs 列表中过滤掉受保护的名称(全部 受保护的名称,因为您要求的是通用名称):
def __str__(self):
attribs = [(k, v) for k, v in self.__dict__.items() if not k.startswith("_")]
for name in dir(self.__class__):
# a protected property is somewhat uncommon but
# let's stay consistent with plain attribs
if name.startswith("_"):
continue
obj = getattr(self.__class__, name)
if isinstance(obj, property):
val = obj.__get__(self, self.__class__)
attribs.append((name, val))
return ' '.join('{}: {}'.format(key, val) for key, val in attribs)
还要注意,这不会处理其他计算属性(property 只是描述符协议的一种通用实现)。在这一点上,对于仍然尽可能通用但可以在需要时自定义的东西的最佳选择是将上述实现为带有几个专门化钩子的 mixin 类:
class PropStrMixin(object):
# add other descriptor types you want to include in the
# attribs list
_COMPUTED_ATTRIBUTES_CLASSES = [property,]
def _get_attr_list(self):
attribs = [(k, v) for k, v in self.__dict__.items() if not k.startswith("_")]
for name in dir(self.__class__):
# a protected property is somewhat uncommon but
# let's stay consistent with plain attribs
if name.startswith("_"):
continue
obj = getattr(self.__class__, name)
if isinstance(obj, *self._COMPUTED_ATTRIBUTES_CLASSES):
val = obj.__get__(self, self.__class__)
attribs.append((name, val))
return attribs
def __str__(self):
attribs = self._get_attr_list()
return ' '.join('{}: {}'.format(key, val) for key, val in attribs)
class YouClass(SomeParent, PropStrMixin):
# here you can add to _COMPUTED_ATTRIBUTES_CLASSES
_COMPUTED_ATTRIBUTES_CLASSES = PropStrMixin + [SomeCustomDescriptor])