我正在为一个类的项目工作,我的代码没有产生与参考代码相同的结果。
我将我的代码与参考代码逐行比较,它们看起来几乎完全相同。一切似乎在逻辑上等同。最终我开始更换线和测试,直到找到重要的线。
原来它是这样的(编辑:确切代码更低):
# 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理解'。
答案 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()根据已经计算过的值给出不同的值。但是如果使用生成器,垃圾收集器可以更快地删除现有值。