Python中使用set作为成员名查找表相比list、dict的优势
问题背景
我在查阅Python标准库inspect.py模块的源码时,看到了如下getmembers函数的实现代码:
def getmembers(object, predicate=None): """Return all members of an object as (name, value) pairs sorted by name. Optionally, only return members that satisfy a given predicate.""" if isclass(object): mro = (object,) + getmro(object) else: mro = () results = [] processed = set() names = dir(object) # :dd any DynamicClassAttributes to the list of names if object is a class; # this may result in duplicate entries if, for example, a virtual # attribute with the same name as a DynamicClassAttribute exists try: for base in object.__bases__: for k, v in base.__dict__.items(): if isinstance(v, types.DynamicClassAttribute): names.append(k) except AttributeError: pass for key in names: # First try to get the value via getattr. Some descriptors don't # like calling their __get__ (see bug #1785), so fall back to # looking in the __dict__. try: value = getattr(object, key) # handle the duplicate key if key in processed: raise AttributeError except AttributeError: for base in mro: if key in base.__dict__: value = base.__dict__[key] break else: # could be a (currently) missing slot member, or a buggy # __dir__; discard and move on continue if not predicate or predicate(value): results.append((key, value)) processed.add(key) results.sort(key=lambda pair: pair[0]) return results
阅读源码后发现,代码中实例化set类作为已处理成员名的存储结构,后续通过if key in processed:语句执行键的存在性查找。
核心疑问:与list、dict等其他Python内置数据结构相比,使用set存储成员名并执行存在性查找具备哪些优势?
set用于该场景的优势
- 查找效率是最核心的优势。
set底层基于哈希表实现,做x in set这类存在性判断的平均时间复杂度是O(1),性能不会随着存储的元素数量增长出现明显下降。如果换用list存储已处理的key,每次查重都要从头遍历整个列表,平均时间复杂度是O(n),处理成员多、继承层级深的对象时,两者的性能差距会非常明显。 - 场景语义匹配度更高。这段逻辑里我们只需要记录「哪些成员名已经被处理过」,不需要给每个名字绑定额外的关联值,也不需要在这个中间存储结构里维持元素顺序(最终返回的结果本来就要单独按名称做排序)。如果用
dict虽然查找效率也能达到O(1),但必须给每个key硬塞一个无意义的value(比如统一存True),平白浪费内存,也不如set直接表达「已处理键的集合」这个含义直观。 - 原生适配去重需求。这段代码本身就会在补录基类的
DynamicClassAttribute时,往names列表里追加重复的键名,set天生就是存储不重复元素的结构,标记已处理键直接调用add()方法即可,不需要像操作list那样每次添加前额外做一次存在判断,代码更简洁,也不容易写出重复处理的逻辑bug。 - 不存在使用限制。这个场景下存储的成员名都是字符串,属于Python内置的可哈希类型,完全满足set对元素的类型要求,不会触发类型错误。
内容的提问来源于stack exchange,提问作者BlueJupiter
相关产品推荐
相关产品推荐

