Skip to main content
 首页 » 编程设计

python 使用 __dict__ 获取对象属性

2025年05月04日15qlqwjy

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

class O(object): 
    def __init__(self): 
        self._a = None 
 
    @property 
    def a(self): 
        return 1 

通过 __dict__(使用 _a)访问属性 a 似乎不会返回属性修饰值,而是返回初始化值 None

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()) 

请您参考如下方法:

当然 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 中 - 如果您想避免这种情况,您还必须从 中过滤掉 protected 名称>attribs 列表(所有 protected 名称,因为您要求的是通用名称):

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 只是描述符协议(protocol)的一种通用实现)。在这一点上,对于仍然尽可能通用但可以根据需要进行自定义的东西,最好的选择是将上面的内容实现为带有几个用于特化的钩子(Hook)的混合类:

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])