简体   繁体   English

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

[英]try-except block in for loop skips NEXT iteration?

I have text data that I am trying to clean for numerical values. 我有试图清除数值的文本数据。 I break it into as clean rows as I can, and separate the rows into data points. 我将其尽可能细分为干净的行,并将这些行分成数据点。 An example is 一个例子是

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

My code should turn that into 我的代码应该将其变成

["1.115","4.3"]

Here is the snippet: 这是代码段:

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

All the print() statements are there for debugging. 所有的print()语句都可用于调试。 Running the code gives 运行代码可以

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

As output. 作为输出。 If there are no two non-floats in a row, it runs fine, but after removing a non-float through the exception handling, it does not print the next float value. 如果连续没有两个非浮点数,则可以正常运行,但是在通过异常处理删除了一个非浮点数后,它不会打印下一个浮点数。

This looks like an issue with modifying a list that you're currently looping over -- by removing an element you've changed the meaning of the cureent offset. 这看起来像是修改当前正在循环的列表的问题-通过删除元素,您已经更改了固化剂偏移量的含义。 One fix is to create a new list instead of changing the original one: 一种解决方法是创建一个新列表,而不是更改原始列表:

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

s = []

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

print(s)

If you really want to the loop to modify the original list, you can try something like this: 如果您确实想循环修改原始列表,则可以尝试如下操作:

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

i = 0

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

print(t)

But make sure you've accounted for all possible cases and test it thoroughly. 但是,请确保您已考虑所有可能的情况并进行了全面测试。

Python (and most languages) have a good chance of getting confused if you're modifying a list while holding an iterator to the list. 如果要在保留列表迭代器的同时修改列表,Python(和大多数语言)很有可能会感到困惑。

This code falls prey to that problem, in that you're modifying the same list you're iterating through. 此代码很容易解决该问题,因为您正在修改要遍历的相同列表。 It's more common to construct a new list that is the output. 构造一个新列表作为输出更为常见。 Here's an example: 这是一个例子:

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

Gets you a result of ['1.115', '4.3'] 得到的结果为['1.115','4.3']

If you want to modify an original list, you can still do it: 如果要修改原始列表,仍然可以执行以下操作:

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

But, if you really want to modify the same list you are iterating while iterating, the best idea is to iterate in reverse: 但是,如果您确实要在迭代时修改要迭代的同一列表,则最好的想法是反向迭代:

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)

Note that I've also used positional deletion, rather than value deletion, which makes it faster (the list doesn't have to get searched another time) 请注意,我还使用了位置删除,而不是值删除,这使其速度更快(列表不必再次搜索)

BTW, you could also consider using a list comprehension: 顺便说一句,您还可以考虑使用列表理解:

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)]

Personally, I think the list comprehension method is the most readable, for this kind of problem. 就我个人而言,我认为列表理解方法对于此类问题最易读。

It's not a good idea to change object you are iterating over. 更改要迭代的对象不是一个好主意。 The list iteration is done index by index, so when you erase one element, remaining elements on the right are shifted down. 列表迭代是逐个索引完成的,因此,当您擦除一个元素时,右侧的其余元素将向下移动。

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"]

The right way of doing this: 正确的方法是:

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)]

Just add .copy() to your loop and remove 'continue' statement: 只需在循环中添加.copy()并删除“ continue”语句:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM