如何循环遍历集合,同时从 Python 中的集合中删除项目 3

How to loop through a set, while removing items from the set in Python 3

这是我的情况:

我有一个 list/set(哪个无关紧要)movieplayer 个对象,我想对其调用 "preload" 函数。此预加载功能可以 return 立即但希望 return 稍后。

我要存储这个movieplayer集合,说明还没有预加载,然后循环遍历,调用preload函数。 preload 函数在 returned 时会将它们从集合中删除(因此我会知道它们何时全部预加载)。

但是,我认为因为 python 正在等待 preload 函数,然后删除播放器,我得到 set size changed during iteration error

嘿,这是我的代码的简化版本,我希望能找到解决此问题的方法。

a = set([mp1, mp2 mp3])
for player in a:
    preload(player)

# preload would be something like
def preload(player):
    player.preloadVideo()
    a.remove(player)
    # This is where I believe the error gets generated.

我能想到的唯一解决方案是对 set a 创建一个 copy,然后遍历它,但我不确定这是否是正确的方法它甚至会起作用。

无需遍历列表 2 次!正如您所说,它会引发 size changed error.So 而不是您可以使用 setlistpop 属性 来获取那些 return 值并将其从数据中删除 structure.For 一个列表,您可以在每次迭代中将 0 索引传递给 pop 也可以作为一种更 pythoinc 的方式,您可以使用 while 而不是for 当您想从数据结构中删除项目时:

a = [mp1, mp2 mp3]
while a:
    preload(a.pop(0))

但是对于 set,pop 不接受索引:

a = set([mp1, mp2 mp3])
while a:
    preload(a.pop())

示例:

>>> def preload(i):
...   print i
... 
>>> a=[1,2,3]
>>> while a:
...     preload(a.pop(0))
... 
1
2
3
>>> a
[]
>>> a={1,2,3}
>>> while a:
...     preload(a.pop())
... 
1
2
3
>>> a
set([])

您可以通过迭代集合的副本来修复它。我在这里使用了list()

a = set(['mp1', 'mp2', 'mp3'])

# preload would be something like
def preload(player):
    player.preloadVideo()
    a.remove(player)

for player in list(a):
    preload(player)    # N.B. pass player, not a

然而,这并不是一个很好的设计。一方面,全局变量 a 是从 preload() 函数中引用的。此外,for 循环遍历集合中的所有元素,依次将每个元素传递给 preload(),因此没有必要检查 a 中每个 player 的成员资格。最后,preload() 应执行预加载播放器所需的任何操作,但不应负责维护外部数据结构 (a)。

更好的设计是 preload() 到 return 一个布尔值,指示预加载是否成功。然后可以在预加载函数之外删除成功加载的播放器:

a = set(['mp1', 'mp2', 'mp3'])

# preload would be something like
def preload(player):
    return player.preloadVideo()    # assume that this returns boolean

for player in list(a):
    if preload(player):
        a.remove(player)

if len(a):
    print "{} player(s) failed to preload: {}".format(len(a), a)        
else:
    print "All players successfully preloaded"

此代码只会在成功预加载后删除播放器。

but would like return a bit in the future.

如果你想异步调用预加载函数,我会使用multiprocessing模块:

from multiprocessing import Pool

a = set([mp1, mp2, mp3])

def preload(player):
    try: # Change it to if/else depending on your type of error handling
        player.preload()
    except:
        return player

p = Pool(5) # uses 5 threads to do the computation, change it accordingly
uninitialized = {players for players in p.map(preload, a) if player is not None}
p.close()