添加到集合并关心它是否有效的 Pythonic 方法?

Pythonic way to add to a set and care about if it worked?

我经常发现,在使用 Pythonic 集时,Pythonic 方式似乎不存在。

例如,做类似 dijkstra 或 a*:

openSet, closedSet = set(nodes), set(nodes)
while openSet:
    walkSet, openSet = openSet, set()
    for node in walkSet:
        for dest in node.destinations():
            if dest.weight() < constraint:
                if dest not in closedSet:
                    closedSet.add(dest)
                    openSet.add(dest)

这是一个弱做作的例子,重点是最后三行:

if not value in someSet:
    someSet.add(value)
    doAdditionalThings()

考虑到 Python 的工作方式,例如,accessing/using 字典的值,我希望能够做到:

try:
    someSet.add(value)
except KeyError:
    continue # well, that's ok then.
doAdditionalThings()

作为一名 C++ 程序员,我的皮肤有点毛骨悚然,我什至做不到:

if someSet.add(value):
    # add wasn't blocked by the value already being present
    doAdditionalThings()

是否有更 Pythonic(如果可能的话更有效)的方法来处理这种 set-as-guard 用法?

添加操作不应该也告诉您该项目是否已经在集合中;它只是确保它在您添加后就在那里。或者换个说法,你要的不是"add an item and check if it worked";你想检查物品是否存在,如果不存在,然后做一些特殊的事情。如果您只想添加项目,则根本不会进行检查。这个模式没有什么不合常规的:

if item not in someSet:
    someSet.add(item)
    doStuff()
else:
    doOtherStuff()

确实 API 可以设计成 .add return 判断物品是否已经在那里,但根据我的经验,这不是特别常见的用途案件。集合的部分要点是您可以自由添加项目而不用担心它们是否已经在那里(因为添加已经包含的项目没有效果)。此外,具有 .add return None 与 Python 内置类型的一般约定一致,这些方法会改变其参数 return None。像 dict.setdefault 这样的事情(它得到一个项目但如果不存在则首先添加它)是不寻常的情况。