是否可以对 Python 中的集合的每个项目应用操作 "in place"?

Is it possible to apply an operation "in place" to every item of a set in Python?

我想删除一组唯一名称中的前缀(如果存在)。

unique_names = {'A_first','A_second','A_third','other'}

一种方法是将集合转换为列表:

unique_names = list(unique_names)

for i, name in enumerate(unique_names):
    if name.startswith('A_'):
        unique_names[i] = name[2:]   

另一种方法,可以创建一个新的集合,如下所述: Apply a operation to every item in a set in Python

然而,这两种解决方案都需要创建一个新对象。 是否可以在不创建新对象的情况下“就地”执行此操作? 如果不是,将操作应用于每个项目的最有效方法是什么?

更新:
@user2357112 supports Monica 找到了一个示例,该示例验证在迭代期间修改集合在 Python 3 中仍然是不安全的。在这种情况下,最简单的事情就是构建一个新集合。

new_unique = {k[2:] if k.startswith('A_') else k for k in unique_names}

如果您需要就地更新集合(例如,您正在更新作为参数传递的集合),您最好清除集合并用新集合更新它。例如,

def update_set(s):
    new_unique = {k[2:] if k.startswith('A_') else k for k in s}
    s.clear()
    s.update(new_unique)

update_set(unique_names)

由于字符串是不可变的,您必须删除旧字符串并将其替换添加到原始字符串中。你可以试试

for x in unique_names:
    if x.startswith('A_'):
        unique_names.add(x[2:])
        unique_names.remove(x)

在 Python 2 中,你会得到一个 RuntimeError: Set changed size during iteration。在 Python 3 中似乎不是这种情况,或者至少在 Python 3.9 中是这样。不过,我并不完全相信这一定是正确的。

你也可以使用集合理解

unique_names = {name[2:] if name.startswith('A_') else name for name in unique_names}

你会遇到2个问题:

  1. 不允许在迭代时更改容器,并且集合没有直接访问器(没有 __getitem__ 方法)
  2. 字符串是不可变的

根据 1. 迭代容器时不能替换元素,根据 2. 不能改变包含的对象。

这意味着您将不得不构建一个新容器并将容器作为一个整体进行替换。 Pythonic 方式是使用集合理解,如 answer to the linked question, or by using

所示