如何高效获取对象列表中第i个属性的求和列表?
Great question—this is such a common pain point when working with objects that have lots of properties, especially when their names aren’t nicely numbered like a1, a2! Let’s break down how to solve this cleanly and efficiently, without hardcoding every single property.
First: Stop Hardcoding Property Names
The key here is to dynamically access the properties of your Foo objects instead of writing x.a1, x.a2, etc. Python gives you a few straightforward ways to do this:
1. Use vars() to Fetch Object Properties
For most simple classes (without __slots__ defined), vars(obj) returns a dictionary of the object’s attributes and values. We can use this to grab all property names from the first object in your list (assuming all Foo objects share the same properties):
# Get all property names from the first object in the list property_names = list(vars(l[0]).keys()) # Calculate sums dynamically with a list comprehension sums = [sum(getattr(obj, prop) for obj in l) for prop in property_names]
getattr(obj, prop)lets us dynamically fetch the value of the property namedpropfromobj—no hardcoding needed.- Using a generator expression (
getattr(...) for obj in l) instead of a list comprehension saves memory, especially with large lists, since we don’t create an intermediate list before summing.
2. Preserve Property Definition Order
If you need the sums to match the exact order in which properties were declared in the Foo class (instead of dictionary order), use these approaches based on your setup:
For Dataclasses (Python 3.7+):
If you define Foo as a dataclass, you can get properties in their original declaration order:
from dataclasses import dataclass, fields @dataclass class Foo: a1: int a2: int a3: int # Get property names in the order they were defined property_names = [field.name for field in fields(Foo)] # Calculate sums sums = [sum(getattr(obj, prop) for obj in l) for prop in property_names]
For Regular Classes:
Use the inspect module to filter for instance attributes (skip methods and class-level properties):
import inspect def get_instance_properties(obj): return [name for name, _ in inspect.getmembers(obj, lambda attr: not inspect.ismethod(attr))] property_names = get_instance_properties(l[0]) sums = [sum(getattr(obj, prop) for obj in l) for prop in property_names]
Optimize for Large Lists: Cut Down on Loop Overhead
Your original approach (and the dynamic list comprehension above) loops through the entire list n times (once per property). If your list l is very large (thousands/millions of objects), you can optimize by looping through the list once and accumulating sums as you go:
if not l: sums = [] # Handle empty list edge case else: # Initialize sums with the first object's property values first_obj = l[0] property_names = list(vars(first_obj).keys()) sums = list(vars(first_obj).values()) # Iterate through remaining objects and add their values to the sums for obj in l[1:]: for idx, prop in enumerate(property_names): sums[idx] += getattr(obj, prop)
This has the same time complexity (O(n*m) where n is property count and m is object count), but it reduces full list traversals from n to 1—this can make a noticeable speed difference with huge datasets.
Key Notes to Avoid Issues
- Consistent Properties: All
Fooobjects in the list must have the same properties. If some objects are missing properties, add a safety check likegetattr(obj, prop, 0)to use 0 as a default value. - Filter Non-Integer Properties: If
Foohas non-integer attributes, filter them out first:property_names = [name for name, val in vars(l[0]).items() if isinstance(val, int)]
内容的提问来源于stack exchange,提问作者LeetCoder

