max([x代表某事物的x])vs max(x代表某事物的x):为什么会有差异,它是什么?

时间:2015-10-25 03:59:46

标签: python python-2.7 list-comprehension

我正在为一个类的项目工作,我的代码没有产生与参考代码相同的结果。

我将我的代码与参考代码逐行比较,它们看起来几乎完全相同。一切似乎在逻辑上等同。最终我开始更换线和测试,直到找到重要的线。

原来它是这样的(编辑:确切代码更低):

# my version:
max_q = max([x for x in self.getQValues(state)])

# reference version which worked:
max_q = max(x for x in self.getQValues(state))

现在,这让我感到困惑。我尝试使用Python(2.7)解释器进行一些实验,使用max在列表推导上运行测试,使用和不使用方括号。结果似乎完全一样。

即使通过PyCharm进行调试,我也没有理由认为我的版本没有产生与参考版本完全相同的结果。到目前为止,我认为我对列表推导的工作方式(以及max()函数如何工作)有很好的处理,但现在我不太确定,因为这是一个奇怪的差异。

这里发生了什么?为什么我的代码产生的结果与参考代码不同(在2.7中)?没有括号的理解中的传递与传递括号的理解有何不同?

编辑2:确切的代码是:

# works
max_q = max(self.getQValue(nextState, action) for action in legal_actions)

# doesn't work (i.e., provides different results)
max_q = max([self.getQValue(nextState, action) for action in legal_actions])

我不认为这应该被标记为重复 - 是的,另一个问题是关于理解对象和列表对象之间的区别,但不是为什么max()在给出'某些列表构建时会提供不同结果的原因通过X理解',而不仅仅是'X理解'。

3 个答案:

答案 0 :(得分:18)

您是否泄漏了影响以后代码的局部变量?

# works
action = 'something important'
max_q = max(self.getQValue(nextState, action) for action in legal_actions)
assert action == 'something important'

# doesn't work (i.e., provides different results)
max_q = max([self.getQValue(nextState, action) for action in legal_actions])
assert action == 'something important'  # fails!

生成器和字典理解创建了一个新的范围,但在py3之前,列表推导没有,为了向后兼容

简便的测试方式 - 将代码更改为:

max_q = max([self.getQValue(nextState, action) for action in legal_actions])
max_q = max(self.getQValue(nextState, action) for action in legal_actions)

假设self.getQValue是纯粹的,那么第一行唯一持久的副作用就是混淆局部变量。如果这打破了它,那么这就是问题的原因。

答案 1 :(得分:7)

在列表推导周围使用[]实际上会在变量中生成一个列表,或者在这种情况下生成一个最大函数。如果没有括号,您将创建一个generator对象,该对象将被输入到max函数中。

results1 = (x for x in range(10))
results2 = [x for x in range(10)]
result3 = max(x for x in range(10))
result4 = max([x for x in range(10)])
print(type(results1)) # <class 'generator'>
print(type(results2)) # <class 'list'>
print(result3) # 9
print(result4) # 9

据我所知,它们应该在max函数中基本相同。

答案 2 :(得分:2)

我不知道为什么你的项目中有不同的价值观,但是当它发生时,我可以给你现场的例子。生成器比列表更有效,因此我们将使用不同的内存。我使用的是Python 3。

此函数返回Python的当前内存使用情况:

import os
import psutil


def memory_usage():
    """Get process virtual memory (vms) usage in MB."""
    process = psutil.Process(os.getpid())
    memory = process.memory_info()[1] / (1024.0 * 1024.0)
    return memory

试试这段代码:

# Generator version:
max_q = max(memory_usage() for i in range(100000))
print(max_q)  # 7.03125

我多次测试了代码,并且在我的机器上获得了超过 7 的代码。

将生成器版本替换为列表版本:

# List version:
max_q = max([memory_usage() for i in range(100000)])
print(max_q)  # 11.44921875

我的机器上有 11 的东西。

如您所见,代码几乎相同,但您会得到不同的输出。

可能在你的项目中getQValue()根据已经计算过的值给出不同的值。但是如果使用生成器,垃圾收集器可以更快地删除现有值。