使用 py3,我有一个使用@property装饰器的对象
class O(object):
def __init__(self):
self._a = None
@property
def a(self):
return 1
Run Code Online (Sandbox Code Playgroud)
访问属性 a via __dict__(with _a) 似乎不返回属性装饰值而是初始化值None
o = O()
print(o.a, o.__dict__['_a'])
>>> 1, None
Run Code Online (Sandbox Code Playgroud)
有没有通用的方法来完成这项工作?我主要需要这个
def __str__(self):
return ' '.join('{}: {}'.format(key, val) for key, val in self.__dict__.items())
Run Code Online (Sandbox Code Playgroud)
当然self.__dict__["_a"]会返回self._a(实际上是相反的 -self._a会返回self.__dict__["_a"]- 但无论如何),而不是self.a. 这里唯一要做的property就是自动调用它的 getter(你的a(self)函数),这样你就不必输入括号,否则它只是一个普通的方法调用。
如果您也想要与属性一起使用的东西,则必须从dir(self.__class__)and手动获取它们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)
Run Code Online (Sandbox Code Playgroud)
请注意,这不会阻止_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)
Run Code Online (Sandbox Code Playgroud)
另请注意,这不会处理其他计算属性(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])
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5034 次 |
| 最近记录: |