for 循环中的 try-except 块跳过 NEXT 迭代?

Posted

技术标签:

【中文标题】for 循环中的 try-except 块跳过 NEXT 迭代?【英文标题】:try-except block in for loop skips NEXT iteration? 【发布时间】:2017-09-10 01:55:28 【问题描述】:

我有一些文本数据,我正在尝试清理数值。我尽可能将其分成干净的行,并将这些行分成数据点。一个例子是

["1.115","","","4.3"]

我的代码应该把它变成

["1.115","4.3"]

这里是sn-p:

for i in t:
    try:
        print(float(i))
    except ValueError:
        print(i)
        t.remove(i)
        continue

所有的 print() 语句都用于调试。运行代码给出了

["1.115","","4.3"]

作为输出。如果连续没有两个非浮点数,它运行正常,但通过异常处理删除一个非浮点数后,它不会打印下一个浮点值。

【问题讨论】:

您正在修改列表。要么复制它,要么从一个空列表开始 【参考方案1】:

这看起来像是修改您当前正在循环的列表的问题——通过删除一个元素,您改变了当前偏移量的含义。一种解决方法是创建一个新列表而不是更改原始列表:

t = ["1.115", "", "", "4.3"]

s = []

for i in t:
    try:
        s.append(float(i))
    except ValueError:
        pass

print(s)

如果你真的想循环修改原始列表,你可以试试这样:

t = ["1.115", "", "", "4.3"]

i = 0

while i < len(t):
    try:
        float(t[i])
        i += 1
    except ValueError:
        del t[i]

print(t)

但请确保您已经考虑了所有可能的情况并进行了彻底的测试。

【讨论】:

【参考方案2】:

如果您在修改列表的同时将迭代器保存到列表中,那么 Python(和大多数语言)很可能会感到困惑。

这段代码是该问题的牺牲品,因为您正在修改您正在迭代的同一个列表。构造一个作为输出的新列表更为常见。这是一个例子:

def yield_only_floats(l):
    for s in l:
        try:
            float(s)
            yield s
        except ValueError:
            pass

x = list(yield_only_floats(["1.115","","","4.3"]))

print x

得到 ['1.115', '4.3'] 的结果

如果您想修改原始列表,您仍然可以这样做:

x = ["1.115","","","4.3"]
x[:] = list(yield_only_floats(x))

但是,如果你真的想在迭代时修改你正在迭代的同一个列表,最好的办法是反向迭代:

def leave_only_floats(l):
    for i in xrange(len(l) - 1, -1, -1):
        try:
            float(l[i])
        except ValueError:
            del l[i]

x = ["1.115","","","4.3"]
leave_only_floats(x)

请注意,我还使用了位置删除,而不是值删除,这使得它更快(不必再次搜索列表)

顺便说一句,您也可以考虑使用列表推导:

def is_float(s):
    try:
        float(s)
        return True
    except ValueError:
        return False

x = ["1.115","","","4.3"]
y = [s for s in x if is_float(s)]

对于这类问题,我个人认为列表推导式是最易读的。

【讨论】:

【参考方案3】:

只需将 .copy() 添加到您的循环中并删除“继续”语句:

for i in t.copy():
    try:
        print(float(i))
    except ValueError:
        print(i)
        t.remove(i)

【讨论】:

【参考方案4】:

更改您正在迭代的对象不是一个好主意。列表迭代是逐个索引完成的,因此当您删除一个元素时,右侧的剩余元素会向下移动。

t = ["1.115", "", "", "4.3"]

for i in t:
    try:
        print(float(i))
    except ValueError:
        print(i)
        t.remove(i)

# First run of loop: 
idx = 0
i = "1.115"
t = ["1.115", "", "", "4.3"]
# Second run of loop
idx = 1
i = ""
t = ["1.115", "", "4.3"]
# Third, last run of loop
idx = 2
i = "4.3"
t = ["1.115", "", "4.3"]

正确的做法:

t = ["1.115","","","4.3"]

def is_float(number):
    try:
        float(number)
        return True
    except ValueError:
        return False

res = [x for x in t if is_float(x)]

【讨论】:

以上是关于for 循环中的 try-except 块跳过 NEXT 迭代?的主要内容,如果未能解决你的问题,请参考以下文章

是否有一种 Pythonic 的方式来跳过 for 循环中的 if 语句以使我的代码运行得更快?

像 while 循环一样,我怎样才能跳过 for 循环中的一个步骤?

跳过 for 循环中的第一个值

★循环中的continue和break语句,写结果题,第5题

如何有条件地跳过python中for循环中的迭代步骤数?

使用 for 循环绘图时,如何跳过图例中的重复标签?