在Python3中,如何在集合中循环,同时从集合中删除项
以下是我的情况: 我有一个在Python3中,如何在集合中循环,同时从集合中删除项,python,python-3.x,iteration,Python,Python 3.x,Iteration,以下是我的情况: 我有一个列表/集合(不管是哪一个)的movieplayer对象,我想调用的“预加载”函数。这个预加载函数可以立即返回,但希望在将来返回一点 我想存储这个电影播放器集合,表明它们还没有被预加载,然后在它们之间循环,调用preload函数。preload函数返回时,会将它们从集合中删除(这样我就知道它们何时都已预加载) 然而,我认为,因为python正在等待预加载函数,然后删除播放器,所以在迭代错误期间,我得到了一个集大小的更改 嘿,这是我的代码的简化版本,我希望能找到一种解决这个
列表/集合
(不管是哪一个)的movieplayer
对象,我想调用的“预加载”
函数。这个预加载函数可以立即返回,但希望在将来返回一点
我想存储这个电影播放器集合,表明它们还没有被预加载,然后在它们之间循环,调用preload
函数。preload
函数返回时,会将它们从集合中删除(这样我就知道它们何时都已预加载)
然而,我认为,因为python正在等待预加载
函数,然后删除播放器,所以在迭代错误期间,我得到了一个集大小的更改
嘿,这是我的代码的简化版本,我希望能找到一种解决这个问题的方法
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.
我能想到的唯一解决方案是将
集合a
复制成副本,然后进行迭代,但我不确定这样做是否正确,或者是否可行。没有必要重复列表2次!正如你所说,它将引发大小更改错误。因此,您可以使用set
和list
的pop
属性来获取返回值的项目,并将其从数据结构中删除。对于列表,您可以在每次迭代中将0索引传递给pop
,这也是您可以使用的一种更为pythoinc的方法当您要从数据结构中删除项时,请使用而不是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
中每个播放器的成员资格。最后,preload()
应该执行预加载播放器所需的任何操作,但它不应该负责维护外部数据结构(a
)
更好的设计是让preload()
返回一个布尔值,指示预加载是否成功。然后可以在预加载功能之外移除成功加载的播放器:
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"
此代码仅在玩家成功预加载后删除该玩家
但我希望将来能回来一点
如果要异步调用preload函数,我将使用以下模块:
你的预加载功能有两个职责,这是一个太多的发布代码,实际上显示了问题-我相信它应该是中的玩家:preload(player)
@PeterWood我想我喜欢你的做法,但你能详细说明一下吗?@mhawke你是对的,我编辑了我的代码,我无法复制精确的代码,因为它依赖于嵌入在外部程序中的电影播放器和python播放器。这看起来很棒。新列表中玩家的id
s是否与a中对应的玩家相同?也就是说,的计算结果是否为真?@Startec是的,它们是相同的对象。.pop()
是正确的选择,正如@Kasra所说,它将用于列表
和设置
(以及更多)而且在copy.fwiw中不会浪费任何东西:当从列表中弹出时,也可以忽略0
,然后从列表的末尾弹出。顺序似乎并不重要…@Kasra,这个方法不是会立即从列表或集合中删除该项吗?我只想在预加载功能完成时删除它们(因为可能有错误,我需要知道哪个玩家没有预加载)@Startec是的,没错!但在这种情况下,因为订单很重要,我们不能这样做@Startec,因此,您可以检查列表或集合中是否存在项目!如果它在集合中
则表示该项目未预加载!
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()