New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
E731 should not apply when assigning to a field #311
Comments
What version of pep8 are you using @mypalmike? I cannot reproduce this using 1.5.7. |
I believe lambda checking was added fairly recently to the tool. I am using version 1.6.0a0 (ships with pydev/eclipse). |
Here's the thing though, just because it is a common pattern, doesn't mean it is a good pattern. Here's what the PEP 8 has to say about this:
E731 is a good addition in my opinion given that. You can easily ignore it (since it seems very specifically targetted to assigning lambda's) with |
I agree that E731 is a good addition. As you mentioned, PEP 8 says, "Always use a def statement instead of an assignment statement that binds a lambda expression directly to a name." The intent appears to be that naming is better accomplished by def than by lambda. In the case I am describing, the code is not naming a function, but rather binding an anonymous function to a field. Unlike the example in PEP8, I can't change: a.b = lambda: "VALUE" to def a.b():
return "VALUE" ... which is syntactically incorrect. The other valid approach would require defining a named function and then setting the field to that function name to achieve the same effect, but it's not clear to me that this is the intent of PEP 8. If PEP 8 is intending to state that lambdas should only be used as arguments to functions, you would think it would be worded in that way. Given the ambiguity of the PEP 8 rule, I'm ok with this being closed. I suspect this will start to bite tkinter and other users of libraries where callbacks are heavily used. |
The language is actually quite clear to me. It says "instead of an assignment statement that binds a lambda expression directly to a name". You're using an assignment statement ( |
I'm not a PEP8 author/expert but it seems weird to me to be expected to use a def statement for something where you can't actually use a def statement. |
It's specifically the case where the assignment statement is equivalent to the one line def statement that the PEP is aiming to provide guidance on. Attribute and item references are not names in that context - it's only referring to standalone identifiers. |
I'll work on a patch to fix this then for later tonight. Thanks for the insight @ncoghlan. |
@mypalmike 397719c should fix this for you. Thanks for reporting it. |
FWIW, I just pushed a tweak to PEP 8 that changes the relevant point from "a name" to "an identifier". Hopefully that's clearer for folks that haven't spent way too much time staring at Python's Grammar file :) |
Thanks Nick! |
Thanks, this definitely clears things up. And the patch addresses the issue for me. I was thinking of some other cases which might trigger this. foo['bar'] = lambda: 'x' # I haven't see this, but could be used to dynamically build jump tables. Something like the following might address all cases directly based on ncoghlan's clarified PEP 8 wording: if before.split('=')[0].strip().isidentifier(): |
@mypalmike any feedback on the latest revision to the PR? |
LGTM. Thanks for your work on this excellent tool. |
Thanks for reporting this bug! |
Fix #311. Add regex to check for field assignment
What about the legitimate case return lambda: whatever ? def _bind(self, func):
'''Takes an unbound method and binds it to :py:var:`self`.'''
return lambda *args, **kwargs: func(self, *args, **kwargs) It is obviously not a direct assignment to an identifier and still produces E731 for me. |
That example can be fixed by using |
While functools.partial might be a workaround in some cases, that isnt the issue. Using return does not bind the lambda to an identifier. |
@jayvdb, exactly. @sigmavirus24, it's a workaround for the pep8 behavior, not a fix, because there's nothing violating PEP8 there (we're not binding the lambda to an identifier and we can't rephrase that with a def of the same identifier - we have to think of an intermediate name). Actually, this workaround is not universal either: one might want to return not a partial application of a function, but a completely fresh function that is a closure over the locals; using a nested def looks times uglier and confuses structure folding in some IDEs. |
I would rephrase the point of PEP8 like this: lambdas are for unnamed functions and it's pointless to use them when you actually need and provide a name via a direct assignment to an identifier (which is really more readable when phrased as a def). |
For example, this code is commonly used for setting the http method in a urllib2 request:
request.get_method = lambda: 'DELETE'
The library is expecting a function, and using a lambda here is not against the PEP8 intent as far as I can tell, which is binding a lambda to a name. This could be done with a def, but the code here is simpler (inasmuch as people find lambda to be simple).
The text was updated successfully, but these errors were encountered: