例如,我们有大量的对象列表:
class KeyStatisticEntry:
def __init__(self, value=""):
self.usedBytes = len(value)
self.encoding = get_string_encoding(value)
@property
def total(self):
overhead = get_object_overhead(self.usedBytes)
if self.encoding == 'some value':
return overhead
else:
return self.usedBytes + overhead
@property
def aligned(self):
return some_func_with(self.usedBytes)
# Here is lots of calculated properties on basis of existing properties
我们需要关注这个对象的许多矩阵 - 它的属性的最小值,最大值,总和,平均值,stdev值。目前我使用这样的代码:
used_bytes = []
total_bytes = []
aligned_bytes = []
encodings = []
for obj in keys.items():
used_bytes.append(obj.usedBytes)
total_bytes.append(obj.total)
aligned_bytes.append(obj.aligned)
encodings.append(obj.encoding)
total_elements = len(used_bytes)
used_user = sum(used_bytes)
used_real = sum(total_bytes)
aligned = sum(aligned_bytes)
mean = statistics.mean(used_bytes)
这是更加“pythonic”的方式,具有更好的性能和内存使用吗?
答案 0 :(得分:1)
您可以使用operator.attrgetter
来获取对象的多个属性,然后使用itertools.zip_longest
(python 2.X中的itertools.izip_longest
)将相关属性附加到一起。
form operator import attrgetter
all_result = [attrgetter('usedBytes','total','aligned','encoding')(obj) for obj in keys.items()]
或者使用生成器表达式来创建生成器而不是列表:
all_result = (attrgetter('usedBytes','total','aligned','encoding')(obj) for obj in keys.items())
然后使用zip_longest
:
used_bytes, total_bytes, aligned_bytes, encodings = zip_longest(*all_results)
然后使用map
函数将sum
函数应用于您需要这些总和的交互项:
used_user, used_real, aligned = map(sum,(used_bytes, total_bytes, aligned_bytes))
分别针对len
和mean
:
total_elements = len(used_bytes)
mean = statistics.mean(used_bytes)
如果您想将所有子列表作为生成器处理(在内存使用方面更优化,运行时性能更低),您可以使用新类来分别使用生成器计算所需的结果:
from itertools import tee
class Aggreegator:
def __init__(self, all_obj):
self.obj = all_obj
self.used_user, self.mean = self.getTotalBytesAndMean()
self.total_elements = len(self.all_obj)
self.aligned = self.getEligned()
def getTotalBytesAndMean(self):
iter_1, iter_2 = tee((obj.usedBytes for obj in self.all_obj))
return sum(iter_1), statistics.mean(iter_2)
def getTotal(self):
return sum(obj.total for obj in self.all_obj)
def getEligned(self):
return sum(obj.aligned for obj in self.all_obj)
def getEncoding(self):
return (obj.encoding for obj in self.all_obj)
然后你可以这样做:
Agg = Aggreegator(keys.items())
# And simply access to attributes
Agg.used_user
答案 1 :(得分:0)
有一种更好的内存使用方法,使用(隐式)生成器而不是列表来获取所有信息。如果您在同一个列表上进行多次计算(例如usedBytes),我不确定它会更好。但请注意,您不能在生成器上使用len
(但长度将是输入列表的长度):
total_elements = len(keys.items())
used_user = sum(obj.usedBytes for obj in keys.items())
used_real = sum(obj.total for obj in keys.items())
aligned = sum(obj.aligned for obj in keys.items())
mean = statistics.mean(obj.usedBytes for obj in keys.items())