python用__dict__获取对象属性

时间:2017-11-22 10:42:09

标签: python python-3.x

使用py3,我有一个使用@property装饰器的对象

class O(object):
    def __init__(self):
        self._a = None

    @property
    def a(self):
        return 1

通过 dict (使用_a)访问属性a似乎没有返回属性修饰值但是初始化值无

o = O()
print(o.a, o__dict__['_a'])
>>> 1, None

有没有通用的方法来使这项工作?

我最需要这个
def __str__(self):
    return ' '.join('{}: {}'.format(key, val) for key, val in self.__dict__.items())

3 个答案:

答案 0 :(得分:3)

当然self.__dict__["_a"]会返回self._a(实际上反之亦然 - self._a将返回self.__dict__["_a"] - 但无论如何),而不是{{ 1}}。 self.a在这里做的唯一事情是自动调用它的getter(你的property函数),这样你就不必输入parens,否则它就是只是简单的方法调用。

如果你想要的东西也适用于属性,你必须从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中 - 如果您想避免这种情况,您还必须从{{1}过滤掉受保护的名称} list(所有受保护的名称,因为你要求通用的东西):

attribs

另请注意,这不会处理其他计算属性(attribs只是描述符协议的一个通用实现)。在这一点上,你最好的选择仍然是尽可能通用,但如果需要可以自定义,可以将上面的内容实现为一个带有几个专业化钩子的mixin类:

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)

答案 1 :(得分:1)

属性基本上是"计算属性"。通常,属性的值不存储在任何地方,它是按需计算的。这就是为什么你无法在__dict__中找到它。

@property装饰器用描述符对象替换类方法,然后将原始方法作为其getter调用。这发生在班级。

o.a的查找从实例开始。它不存在,下一步检查类。 O.a存在并且是描述符(因为它具有描述符协议的特殊方法),因此调用描述符的getter并使用返回的值。

(编者) 没有通用的方法来转储名称:描述符的值对。必须检查包括基础在内的类,这部分并不困难。但是,检索值等同于函数调用,并且可能具有意外和不期望的副作用。对于不同的观点,我想在这里引用bruno desthuilliers的评论:&#34; 属性get不应该有不必要的副作用(如果它确实那么那么明显的设计错误)< / EM>&#34;

答案 2 :(得分:0)

您还可以将self._a更新为getter,因为getter的返回应始终反映存储的self._a

class O(object):
    def __init__(self):
        self._a = self.a

    @property
    def a(self):
        self._a = 1
        return self._a

也许有点多余,但是在这种情况下,最初设置self._a = None没用。

如果您需要二传手,

如果删除getter的第一行,这也将是兼容的:

@a.setter
def a(self, value):
    self._a = value