Python如何处理列表推导中的多个条件?

mak*_*day 3 python list

我试图从我的函数创建一个列表理解,我遇到了一个意外的行为.为了更好地理解,我的函数得到一个整数并检查它的哪个数字完全除以整数:

# Full function
divs = list()
for i in str(number):
    digit = int(i)
    if digit > 0 and number % digit == 0:
        divs.append(digit)
return len(divs)

# List comprehension
return len([x for x in str(number) if x > 0 and number % int(x) == 0])
Run Code Online (Sandbox Code Playgroud)

问题是,如果我给出一个1012输入,则返回完整的函数3,这是预期的结果.列表理解返回一个ZeroDivisionError: integer division or modulo by zero.我明白这是因为这个条件:

if x > 0 and number % int(x) == 0
Run Code Online (Sandbox Code Playgroud)

在完整功能中,多个条件从左到右处理,所以很好.在列表理解中,我真的不知道,但我猜测它没有以同样的方式处理.

直到我尝试使用更简单的功能:

# Full function
positives = list()
for i in numbers:
    if i > 0 and 20 % i ==0:
        positives.append(i)
return positives

# List comprehension
return [i for i in numbers if i > 0 and 20 % i == 0]
Run Code Online (Sandbox Code Playgroud)

他们俩都工作了.所以我想也许它与它有关number % int(x)?这只是对它如何真正起作用的好奇心?有任何想法吗?

Sha*_*ger 6

该列表理解是不同的,因为你比较x > 0没有转换x到int.在Py2中,不匹配的类型将以任意和愚蠢但一致的方式进行比较,在这种情况下,将所有strs(类型x)视为大于所有int(类型0),这意味着x > 0测试始终True是第二个测试总是执行(有关此废话的详细信息,请参阅下面的脚注).将列表理解更改为:

[x for x in str(number) if int(x) > 0 and number % int(x) == 0]
Run Code Online (Sandbox Code Playgroud)

它会起作用.

请注意,您可以通过map在代码顶部导入Py3版本(from future_builtins import map并使用生成器表达式sum而不是列表解析)来进一步简化(并限制冗余工作和内存消耗)len:

return sum(1 for i in map(int, str(number)) if i > 0 and number % i == 0)
Run Code Online (Sandbox Code Playgroud)

int每个数字只调用一次,并且不构造中间数list.


脚注:0是一种数字类型,并且所有数字类型都比"除外"更小None,因此a str总是大于0.在非数字的情况下,这将是比较字符串类型的名字,所以dict< frozenset< list< set< str< tuple,除哎呀,frozenset和set比较"自然地"给对方,这样你就可以有非传递关系; frozenset() < []是真的,[] < set()是真的,但是frozenset() < set()是假的,因为特定类型的比较器在最终版本中被调用.就像我说的那样,任意而混乱; 它是从Python 3中删除的原因.