简体   繁体   English

使用isinstance从列表中删除false时的问题

[英]Issue when removing false from list with isinstance

So, I was messing around removing non-integers from a list in Python (very exciting stuff). 因此,我在弄乱从Python列表中删除非整数的事情(非常令人兴奋的东西)。 I came across an issue with the following code that I cannot seem to resolve: 我遇到了以下似乎无法解决的代码问题:

list_a = ["a", 1, 2, 3, False, [1, 2, 3]]

for item in list_a:
    if not isinstance(item, int):
        list_a.remove(item)

I'm trying to remove all non int items in the list but the the above code does not remove False. 我正在尝试删除列表中的所有非int项目,但以上代码并未删除False。

What I want: [1, 2, 3] 我想要的是: [1, 2, 3]

What I'm getting: [1, 2, 3, False] 我得到的是: [1, 2, 3, False]

Any help figuring this out would be much appreciated! 任何帮助弄清楚这一点将不胜感激!

Your issue is that bool is a subclass of int : 您的问题是bool int的子类:

>>> issubclass(bool, int)
True

Therefore, all bools are ints (where False is 0 and True is 1) and could be used for indexing and such. 因此,所有布尔值都是整数(其中False为0,True为1),可用于索引等。 You can test type(item) is bool instead. 您可以测试type(item) is bool

In Python, bool is a subclass of int : 在Python中, boolint的子类:

>>> isinstance(True, int)
True
>>> isinstance(True, bool)
True

This means that you need a more refined check. 这意味着您需要更精细的检查。 You could, for example, check that type(item) == int . 例如,您可以检查type(item) == int

For background, see PEP 285 : 有关背景,请参见PEP 285

6) Should bool inherit from int?

    => Yes.

       In an ideal world, bool might be better implemented as a
       separate integer type that knows how to perform mixed-mode
       arithmetic.  However, inheriting bool from int eases the
       implementation enormously (in part since all C code that calls
       PyInt_Check() will continue to work -- this returns true for
       subclasses of int).  Also, I believe this is right in terms of
       substitutability: code that requires an int can be fed a bool
       and it will behave the same as 0 or 1.  Code that requires a
       bool may not work when it is given an int; for example, 3 & 4
       is 0, but both 3 and 4 are true when considered as truth
       values.

Another, unrelated, issue is that you're modifying a list while iterating over it. 另一个不相关的问题是,您在迭代列表时正在修改列表。 Have a read of Modifying list while iterating and links therein. 迭代时请阅读“ 修改列表”及其中的链接。

This results in a subtle bug in your code. 这会在您的代码中产生一个细微的错误。 For example, it fails to remove "b" from the following list (try it!): 例如,它无法从以下列表中删除"b" (尝试!):

list_a = ["a", "b", 1, 2, 3]

for item in list_a:
    if not isinstance(item, int):
        list_a.remove(item)

One clean way to fix this is by using a list comprehension. 解决此问题的一种干净方法是使用列表理解。

Check not if an item is an instance of something. 检查项目是否是某事物的实例。 Check its type directly: 直接检查其类型:

[x for x in list_a if type(x)==int]

[1, 2, 3] [1,2,3]

You are making two errors here: 您在这里犯了两个错误:

  • Assuming isinstance works with bool (others have explained how bool actually sub-classes from int ). 假设isinstancebool (其他人已经解释了bool实际上是如何从int子类化的)。
  • Altering a list while you iterate through it 遍历列表时更改列表

This may be one of those cases where explicitly testing using type(val) == int is warranted: 这可能是其中需要使用type(val) == int进行显式测试的情况之一:

list_a = ["a", 1, 2, 3, False, [1, 2, 3]]

for item in list_a[:]:
    if not type(item) == int:
        list_a.remove(item)

which yields the wanted result; 产生想要的结果; notice how list_a is copied with [:] assuring we iterate over all its contents despite removing from it. 请注意如何使用[:]复制list_a ,以确保尽管从列表中删除了所有内容,但仍对其进行了迭代。

In a comprehension form, this is prettier: 以一种理解的形式,这更漂亮:

res = [i for i in list_a if type(i) == int]

A clear way to do it. 一种清晰的方法。

list_a = ["a", 1, 2, 3, False, [1, 2, 3]]
list_b = []
for item in list_a:
    if isinstance(item, int) and not isinstance(item, bool):
        list_b.append(item)
print list_b

Output 输出量

[1, 2, 3]

Bool is a subclass of Int, furthermore type() and isinstance() should not be confused. Bool是Int的子类,此外,type()和isinstance()不应混淆。 This is because before boolean became its own class "1"s and "0"s represented True and False respectively. 这是因为在布尔值成为其自己的类之前,“ 1”和“ 0”分别表示True和False。

As a result you should use type() due to inheritance. 结果,由于继承,您应该使用type()。

def f(randomList):
    result = []
    for elem in randomList:
        if type(elem)==int:
            result.append(elem)
    return result

This is a non-destructive modified list because sometimes modifying a list you're iterating through can cause errors or be a pain at least. 这是一个非破坏性的已修改列表,因为有时修改您要遍历的列表可能会导致错误或至少引起痛苦。

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

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