为什么这个列表理解将负值而不是正值转换为0?

时间:2017-01-20 11:50:24

标签: python list list-comprehension

我希望将列表中的所有负值转换为0.为了做到这一点,我有两种不同的方法,而我只理解为什么两种方法中的第一种方法都以它的方式工作。这是一个例子:

values = [200, 400, 50, -20, -100, 90, 780, -600]
n2z_one = [0 if v < 0 else v for v in values] # approach one
n2z_two = [v*(v>0) for v in values] #approach two

结果是:

values: [200, 400, 50, -20, -100, 90, 780, -600]
n2z_one: [200, 400, 50, 0, 0, 90, 780, 0]
n2z_one: [200, 400, 50, 0, 0, 90, 780, 0]

我的问题是v*(v>0)。不应该这意味着,理解会查找值大于而不是0并将它们乘以0,而不是查找小于的值而不是0并将它们乘以0 ?

3 个答案:

答案 0 :(得分:3)

(v>0)生成布尔对象TrueFalse。 Boolean是整数的子类,True的整数值为1,False为整数值0

>>> issubclass(bool, int)
True
>>> int(True)
1
>>> int(False)
0

当您使用带有算术运算符的布尔对象时,它将被视为整数。

因此,如果v 小于或等于0 ,则(v>0)会生成False,如果在乘法中使用0的整数值使用:

>>> v = 42
>>> v > 0
True
>>> v * True
42
>>> v = -81
>>> v > 0
False
>>> v * False
0

使用像这样的布尔测试是纯粹的混淆。不要在生产代码中使用它,它只会让读者感到困惑。

比条件表达式方法更慢

>>> from timeit import timeit
>>> from random import randint
>>> values = [randint(-10**6, 10**6) for _ in range(1000)]
>>> timeit('[0 if v < 0 else v for v in values]', 'from __main__ import values', number=10000)
0.4128753509976377
>>> timeit('[v*(v>0) for v in values]', 'from __main__ import values', number=10000)
0.5792852119993768

基于布尔测试在两个引用(v0)之间进行选择比乘法更快。我是否提到使用像这样的布尔值会产生难以理解的混乱并且永远不应该使用?

答案 1 :(得分:1)

布尔值被强制转换为等效数字,1True0False

如果数字较大,您将获得1,乘以数字本身。

否则您将获得0,其乘以任何数字0

答案 2 :(得分:0)

v > 0粗略地说,如果是1,则转换为True,否则转换为0

我们假设v = 5。然后我们得到v*(v>0) == 5*(5>0) == 5*True == 5 * 1 == 5

现在让我们看看v = -5时会发生什么。然后v*(v>0) == -5*(-5>0) == -5*False == -5 * 0 == 0