获取容器python中所有项的属性

时间:2012-04-27 13:42:22

标签: python

我有以下(显然是简化的)类

class A(object)
    def __init__(self, a):
        self.a = a
        self.b = 'b'
        # Other class attributes are added


class B(list):
    """
    Some customization of this class...
    """
    pass

BB = B([A(i) for i in range(10)])

我想做

B.a

并获取a中每个包含项目的所有B属性的列表。我知道为了做到这一点,我需要覆盖__getattr__,但我不确定实现它的最佳方法。这需要是通用的,因为B不知道可能需要访问的A的任何属性。

有人可以就这个想法的实施提出一些建议吗?

1 个答案:

答案 0 :(得分:5)

一般解决方案:

如果您希望全面开展工作,那么您可以按照您的想法覆盖__getattr__()

class A(object):
    def __init__(self, a):
        self.a = a
        self.b = a-1

class B(list):
    """
    Some customization of this class...
    """
    def __getattr__(self, name):
        return (getattr(item, name) for item in self)

bb = B([A(i) for i in range(10)])
print(list(bb.a))
print(list(bb.b))

给我们:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[-1, 0, 1, 2, 3, 4, 5, 6, 7, 8]

请注意,__getattr__()仅在属性尚不存在时才会被调用。因此,如果您将bb.b设置为其他值,则可以改为:

bb = B([A(i) for i in range(10)])
bb.b = 5
print(list(bb.a))
print(bb.b)

给我们:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
5

示例显示B不需要知道它的内容:

>>> import datetime
>>> b = B([datetime.date(2012, 1, 1), datetime.date(2012, 2, 2), datetime.date(2012, 3, 3)])
>>> list(b.month)
[1, 2, 3]

原始答案:

最简单的方法是使用generator expression

class B(list):
    """
    Some customization of this class...
    """
@property
def a(self):
    return (item.a for item in self)

此生成器表达式相当于:

@property
def a(self):
    for item in self:
        yield item.a

我还使用the property() builtin作为装饰器,使B.a充当属性而不是函数。

我们可以这样做:

bb = B([A(i) for i in range(10)])
print(list(bb.a))

并获得:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

如果你肯定想要一个列表而不是迭代器,你可以使用列表推导([item.a for item in self]),但通常迭代器更有用,并且可以很容易地变成一个列表(如图所示)上文)。

请注意,您还可以通过分配生成器表达式来更简单地执行此操作:

class B(list):
        """
        Some customization of this class...
        """
    def __init__(self, *args):
        super(B, self).__init__(*args)
        self.a = (item.a for item in self)

然而,这意味着第一次使用后发电机将耗尽,所以我会反对它。