我有以下(显然是简化的)类
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
的任何属性。
有人可以就这个想法的实施提出一些建议吗?
答案 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)
然而,这意味着第一次使用后发电机将耗尽,所以我会反对它。