I was working on a project for class where my code wasn't producing the same results as the reference code.
I compared my code with the reference code line by line, they appeared almost exactly the same. Everything seemed to be logically equivalent. Eventually I began replacing lines and testing until I found the line that mattered.
Turned out it was something like this (EDIT: exact code is lower down):
# 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))
Now, this baffled me. I tried some experiments with the Python (2.7) interpreter, running tests using max
on list comprehensions with and without the square brackets. Results seemed to be exactly the same.
Even by debugging via PyCharm I could find no reason why my version didn't produce the exact same result as the reference version. Up to this point I thought I had a pretty good handle on how list comprehensions worked (and how the max()
function worked), but now I'm not so sure, because this is such a weird discrepancy.
What's going on here? Why does my code produce different results than the reference code (in 2.7)? How does passing in a comprehension without brackets differ from passing in a comprehension with brackets?
EDIT 2: the exact code was this:
# 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])
I don't think this should be marked as duplicate -- yes, the other question regards the difference between comprehension objects and list objects, but not why max()
would provide different results when given a 'some list built by X comprehension', rather than 'X comprehension' alone.
The max() function returns the largest item in an iterable. It can also be used to find the largest item between two or more parameters.
max() in a Set The built-in function max() in Python is used to get the maximum of all the elements in a set.
The time complexity of the python max function is O(n). We can apply it on the string, which is not possible in other languages. These types of built-in functions make python a great language.
Are you leaking a local variable which is affecting later code?
# 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!
Generator and dictionary comprehensions create a new scope, but before py3, list comprehensions do not, for backwards compatibility
Easy way to test - change your code to:
max_q = max([self.getQValue(nextState, action) for action in legal_actions])
max_q = max(self.getQValue(nextState, action) for action in legal_actions)
Assuming self.getQValue
is pure, then the only lasting side effect of the first line will be to mess with local variables. If this breaks it, then that's the cause of your problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With