我怀疑这是 Python for 的一个 bug

2020-04-18 16:04:36 +08:00
 smallgoogle
# -*- coding: utf-8 -*-

from multiprocessing import Pool
import os, time, random


def worker(msg, ip):
    t_start = time.time()
    print("%s 开始执行, ip:%s, 进程号为%d" % (msg['id'], ip['ip'], os.getpid()))
    time.sleep(random.random() * 2)
    # time.sleep(2)
    t_stop = time.time()
    print(msg['id'], "执行完毕, ip:%s, 耗时%0.2f" % (ip['ip'], t_stop - t_start))


def start(d):
    po = Pool(10)
    a_list = [
        {"ip": "ip - 1"},
        {"ip": "ip - 2"}
    ]
    d_list = d
    for_times = 0
    while len(d_list) > 0:
        print("第 %s 次" % (for_times))
        x = 0
        for i in d_list:
            if x < 2:
                po.apply_async(worker, (i, a_list[for_times]))
                d_list.pop(x)
                x+=1
            else:
                print("==============")
                break
        for_times += 1
    print("----start----")
    po.close()
    po.join()
    print("----end----")



if __name__ == '__main__':
    d = [{
        "id": 1,
        "keyword": "site:www.aaa.com 灯",
        "site": "www.aaa.com"
    }, {
        "id": 2,
        "keyword": "site:www.bbb.com 灯",
        "site": "www.bbb.com"
    }, {
        "id": 3,
        "keyword": "site:www.ccc.com 灯",
        "site": "www.ccc.com"
    }, {
        "id": 4,
        "keyword": "site:www.ddd.com 灯",
        "site": "www.ddd.com"
    }]
    start(d)

这段代码没问题。可是会报错;我 debug 了。就是 for 里面的 if 的问题。
理论上 whlie 两次就结束了。可是为啥这里 whlie 走了三次呢?
while 第二次的时候,会看到 for 里面的 if 没生效了。
这是不是 python 的 bug ?

我已经排两天。无结果。

2351 次点击
所在节点    Python
16 条回复
GrayXu
2020-04-18 16:21:28 +08:00
没看代码…但觉得是 python 的 bug ?
yingo
2020-04-18 16:24:38 +08:00
第 0 次
第 1 次
第 2 次
Traceback (most recent call last):
File "D:\python\dict.py", line 61, in <module>
start(d)
File "D:\python\dict.py", line 29, in start
po.apply_async(worker, (i, a_list[for_times]))
IndexError: list index out of range

for i in d_list:
...
d_list.pop()
...

别写这种代码.
renmu
2020-04-18 16:28:45 +08:00
不要一边对列表修改一边进行判断,会引起奇怪的问题。想复制的话可以采用 list.copy(),而不是直接等于
NeinChn
2020-04-18 16:29:37 +08:00
d_list.pop(x)是咋想的。。。
xiri
2020-04-18 16:30:00 +08:00
调试看了一下,没问题啊,最后是数组越界了,主要就是你在 for 循环里面弹出 d_list 中的元素导致的,你自己去看看每次循环的时候 d_list 变成啥样了,i 是啥就知道了,还有,最好不要写下面这样的代码,出问题能让你头痛死
for i in d_list:
......
d_list.pop(x)
......
DGideas
2020-04-18 16:32:02 +08:00
你的程序的输出结果是什么?

贴代码到这里来问问题,没有描述解释器和操作系统环境,别人复现你的问题也不一定准啊
Jirajine
2020-04-18 16:32:19 +08:00
你在迭代时修改了迭代对象本身,当然会产生难以预料的行为。
一个简单的做法是在目标对象的复制上迭代,
将 for i in d_list: 修改为 for i in list(d_list):
wysnylc
2020-04-18 16:32:42 +08:00
人类总是觉得机器有问题而不是自己有问题
yingxiangyu
2020-04-18 16:36:48 +08:00
循环过程中不要修改循环的列表,你 pop 了列表就变了,第二次循环开始是 2 元素,pop 一个变 1 元素,这个 for 还要不要接着执行
imn1
2020-04-18 16:41:19 +08:00
看标题还没看正文就想,是不是又是增减列表的问题
进来一看果然……
freakxx
2020-04-18 16:43:40 +08:00
首先这标题就够标题了

import 的时候,这样写是好的
import os
import random
import time

然后
都用到 py3 了,多用用 f,或者 format

要随机 1-2s
直接用 random.uniform(0, 2)


while 嵌套 for 这种也挺不好看的

不需要特殊判断的话 while d_list 就可以了

需要判断第 N 次的话,直接用
for index, value in enumerate(d_list)

不要一边遍历 list 一般修改




==============

所以不要搞个大新闻
superrichman
2020-04-18 16:46:51 +08:00
d_list.pop(x) 问题出在这里,仔细琢磨一下你要 pop 出来的元素和下标为 x 的是不是同一个。
smallgoogle
2020-04-18 16:48:37 +08:00
@freakxx 我的需求实际上用 enumerate 是无法解决的。 = = 还是需要用 list 。

@imn1 所以你有啥解决方案?我比较想优雅的解决。
cassidyhere
2020-04-18 19:49:15 +08:00
用队列。。。
ifzzzh
2020-04-18 22:13:51 +08:00
@smallgoogle #13 你都用 x<2 做判断了为什么不直接拿 x 做循环变量呢
ieric
2020-04-18 23:56:13 +08:00
@freakxx 还有多余代码 d_list=d ?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/663761

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX