Some people write somename = lambda args: expression instead of the more obvious (to most people) and, dare I say, standard def somename(args): return expression The difference in the result (the only one I know of) is that the code and function objects get the generic name '<lambda>' instead of the more informative (in repr() output or tracebacks) 'somename'. I consider this a disadvantage. In the absence of any compensating advantages (other than the trivial saving of 3 chars), I consider the def form to be the proper Python style to the point I think it should be at least recommended for the stdlib in the Programming Recommendations section of PEP 8. There are currently uses of named lambdas at least in urllib2. This to me is a bad example for new Python programmers. What do our style mavens think? Terry Jan Reedy
Agreed, I tend to pick these out of style reviews at Google.
On Fri, May 2, 2008 at 4:03 PM, Terry Reedy
Some people write somename = lambda args: expression instead of the more obvious (to most people) and, dare I say, standard def somename(args): return expression
The difference in the result (the only one I know of) is that the code and function objects get the generic name '<lambda>' instead of the more informative (in repr() output or tracebacks) 'somename'. I consider this a disadvantage.
In the absence of any compensating advantages (other than the trivial saving of 3 chars), I consider the def form to be the proper Python style to the point I think it should be at least recommended for the stdlib in the Programming Recommendations section of PEP 8.
There are currently uses of named lambdas at least in urllib2. This to me is a bad example for new Python programmers.
What do our style mavens think?
Terry Jan Reedy
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/guido%40python.org
-- --Guido van Rossum (home page: http://www.python.org/~guido/)
+1 from me
On May 2, 2008, at 7:03 PM, "Terry Reedy"
Some people write somename = lambda args: expression instead of the more obvious (to most people) and, dare I say, standard def somename(args): return expression
The difference in the result (the only one I know of) is that the code and function objects get the generic name '<lambda>' instead of the more informative (in repr() output or tracebacks) 'somename'. I consider this a disadvantage.
In the absence of any compensating advantages (other than the trivial saving of 3 chars), I consider the def form to be the proper Python style to the point I think it should be at least recommended for the stdlib in the Programming Recommendations section of PEP 8.
There are currently uses of named lambdas at least in urllib2. This to me is a bad example for new Python programmers.
What do our style mavens think?
Terry Jan Reedy
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/jnoller%40gmail.com
Alex Martelli wrote:
On Fri, May 2, 2008 at 4:11 PM, Jesse Noller
wrote: +1 from me
+2 from me -- of all abuses of lambdas, this one's the worst.
What Alex said :) Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://www.boredomandlaziness.org
On Fri, 2 May 2008 19:03:55 -0400
"Terry Reedy"
Some people write somename = lambda args: expression instead of the more obvious (to most people) and, dare I say, standard def somename(args): return expression [...] There are currently uses of named lambdas at least in urllib2. This to me is a bad example for new Python programmers.
What do our style mavens think?
Speaking as one of those "some people", my position is that functions created with lambda are first-class objects the same as everything else in Python, and a rule that says "You must not assign a lambda to a name, ever" would be a terrible rule. (And I don't do it to save three characters. I don't do it often, and I can't exactly articulate why I do it, only that I do it when it feels right. It's a style thing.) However, I'm happy for "no named lambdas" to be a guideline or recommendation. I'm even happy for a stronger prohibition to apply to the standard library. I don't dislike named lambdas, but I don't expect others to like them. -- Steven D'Aprano
Steven schrieb:
Speaking as one of those "some people", my position is that functions created with lambda are first-class objects the same as everything else in Python, and a rule that says "You must not assign a lambda to a name, ever" would be a terrible rule.
PEP 8 is for the standard library and Python core only. You can write your own code like you prefer. Nobody is going to enforce the PEP 8 style guide unless you write code for the stdlib. (By the way +1 from me, too). Christian
Christian Heimes schrieb:
Steven schrieb:
Speaking as one of those "some people", my position is that functions created with lambda are first-class objects the same as everything else in Python, and a rule that says "You must not assign a lambda to a name, ever" would be a terrible rule.
PEP 8 is for the standard library and Python core only. You can write your own code like you prefer. Nobody is going to enforce the PEP 8 style guide unless you write code for the stdlib.
Well, most sane people I know use it at least as a strong guideline for their own code as well, so we should always consider the impact when changing PEP 8. This specific case though is a good guideline to have. Georg -- Thus spake the Lord: Thou shalt indent with four spaces. No more, no less. Four shall be the number of spaces thou shalt indent, and the number of thy indenting shall be four. Eight shalt thou not indent, nor either indent thou two, excepting that thou then proceed to four. Tabs are right out.
On 2-May-08, at 4:03 PM, Terry Reedy wrote:
Some people write somename = lambda args: expression instead of the more obvious (to most people) and, dare I say, standard def somename(args): return expression
The difference in the result (the only one I know of) is that the code and function objects get the generic name '<lambda>' instead of the more informative (in repr() output or tracebacks) 'somename'. I consider this a disadvantage.
In the absence of any compensating advantages (other than the trivial saving of 3 chars), I consider the def form to be the proper Python style to the point I think it should be at least recommended for the stdlib in the Programming Recommendations section of PEP 8.
There are currently uses of named lambdas at least in urllib2. This to me is a bad example for new Python programmers.
What do our style mavens think?
I'm not a style maven, but I'll put forward why I don't think this is bad style. Most importantly, these statements can result from sensible changes from what is (I believe) considered good style. For example, consider: registerCallback(lambda: frobnicate(7)) what if there are too places that the callback needs to be registered? registerCallback(lambda: frobnicate(7)) registerCallback2(lambda: frobnicate(7)) DRY leads to factoring this out into a variable in a straightforward manner: callback = lambda: frobnicate(7) registerCallback(callback) registerCallback2(callback) Another thing to consider is that the def() pattern is only possible when the bound variable has no dots. A common pattern for me is to replace an instances method with a lambda to add monitoring hooks or disable certain functionality: inst.get_foo = lambda: FakeFoo() This is not replacable in one line with a def (or without locals() detritius). Assuming this is good style, it seems odd that inst.get_foo = lambda: FakeFoo() is acceptible style, but get_foo = lambda: FakeFoo() isn't. (I also happen to think that the def pattern is less clear in some situations, but that speaks more to personal taste so isn't particularly relevant) -Mike
Mike Klaas wrote:
... A common pattern for me is to replace an instances method with a lambda to add monitoring hooks or disable certain functionality: inst.get_foo = lambda: FakeFoo() This is not replacable in one line with a def (or without locals() detritius). Assuming this is good style, it seems odd that inst.get_foo = lambda: FakeFoo() is acceptible style, but get_foo = lambda: FakeFoo() But surely, none of these are great style, and in fact the lambda lures you into using it.
I'd propose a far better use is: inst.get_foo = FakeFoo or get_foo = FakeFoo --Scott David Daniels Scott.Daniels@Acm.Org
On 2-May-08, at 11:23 PM, Scott David Daniels wrote:
Mike Klaas wrote:
... A common pattern for me is to replace an instances method with a lambda to add monitoring hooks or disable certain functionality: inst.get_foo = lambda: FakeFoo() This is not replacable in one line with a def (or without locals() detritius). Assuming this is good style, it seems odd that inst.get_foo = lambda: FakeFoo() is acceptible style, but get_foo = lambda: FakeFoo() But surely, none of these are great style, and in fact the lambda lures you into using it.
I'd propose a far better use is: inst.get_foo = FakeFoo or get_foo = FakeFoo
Sorry, that was a bad example. It is obviously silly if the return value of the function is callable. -Mike
On Fri, May 2, 2008 at 11:32 PM, Mike Klaas
Sorry, that was a bad example. It is obviously silly if the return value of the function is callable.
...and yet it's *exactly* what keeps happening to lambda-happy programmers -- in production code as well as examples, and in major/famous projects too. E.g., a simple google code search shows many Zope versions containing "Bucket=lambda:{}" instead of the obvious "Bucket=dict", Chandler with an intricate t = threading.Thread(target=lambda x=activePort:testcon(x),verbose=0) instead of t = threading.Thread(target=testcon, args=(activePort,), verbose=0) SQLAlchemy with "callable_=lambda i: self.setup_loader(i)" instead of "callable_=self.setup_loader" ... apparently the existence of lambda may easily blind one to the fact that one can simply pass a callable. I guess that's inevitable (given lambda's existence... and human nature;-) and about on the same plane as another hatefully redundant construct I find myself having to beat upon over and over in code reviews: if <expression>: result = True else: result = False return result vs the simple "return <expression>" [[or bool(<expression>) if it's actually mandatory to return a bool and <expression> can't be relied upon to produce one]]. Alex
I guess that's inevitable (given lambda's existence... and human nature;-) and about on the same plane as another hatefully redundant construct I find myself having to beat upon over and over in code reviews:
if <expression>: result = True else: result = False return result
vs the simple "return <expression>" [[or bool(<expression>) if it's actually mandatory to return a bool and <expression> can't be relied upon to produce one]].
Indeed, I think these are the same phenomenons. If lambdas where not available, people would, instead of writing Thread(target = lambda: foo()) write def target(): foo() Thread(target = target) Your example above demonstrates that the boolean type is a concept that is *very* difficult to grasp (not the notion of boolean expressions, which are easy to understand - it's the boolean *type* that is difficult, i.e. that a boolean expression can be used not just in conditional statements, but also assigned to variables, returned, etc.). When I ask students in the exam to rewrite your code above (and assuming they use Java), so that "it is a single line", they typically write return <expression> ? true : false; Likewise, apparently, the notion of generic callables is difficult to understand. Unless you have written it yourself, you won't recognize an expression as callable. Regards, Martin
On Sun, 4 May 2008 01:24:54 am Alex Martelli wrote:
On Fri, May 2, 2008 at 11:32 PM, Mike Klaas
wrote: ... Sorry, that was a bad example. It is obviously silly if the return value of the function is callable.
...and yet it's *exactly* what keeps happening to lambda-happy programmers -- in production code as well as examples, and in major/famous projects too. E.g., a simple google code search shows many Zope versions containing "Bucket=lambda:{}" instead of the obvious "Bucket=dict",
In fairness, up until a few years ago, Bucket=dict wouldn't have worked. I'm sure there's a lot of Python programmers who learnt the language with version < 2.0 who still have blind-spots when it comes to types. I know I do (but I'm getting better with practice). Besides, would that be any better written as this? def Bucket(): return {} I think not. This is not a "named lambda" problem, this is a "developer doesn't know how to use types" problem. While we're discussing named lambdas, and at the risk of dragging this thread out even longer, here's one example where I would use one: def parrot(args, transformation=None): if transformation is None: # Use an identity function. transformation = lambda x: x for arg in args: do_something_with(transformation(arg)) Does anybody have any constructive comments to make about this usage? -- Steven D'Aprano
Mike Klaas wrote:
Another thing to consider is that the def() pattern is only possible when the bound variable has no dots. A common pattern for me is to replace an instances method with a lambda to add monitoring hooks or disable certain functionality:
inst.get_foo = lambda: FakeFoo()
Good point. That one may write eg for inst.bar in range(10) : do_something() makes one wonder whether def inst.bar(...) : ... or even def fn[k](...) : ... should be similarly permitted. Has this ever been discussed ? Regards, BB
Boris Borcic wrote:
def inst.bar(...) : ... def fn[k](...) : ...
should be similarly permitted. Has this ever been discussed ?
Yes, but there didn't seem to be much interest in the idea. Which is disappointing, because it would be ideal for setting up function tables and such like. One small problem is that there would be no sensible name to give the function object, but that's no worse than what you get when using a lambda. -- Greg
On Sat, May 3, 2008 at 1:03 AM, Terry Reedy
Some people write somename = lambda args: expression instead of the more obvious (to most people) and, dare I say, standard def somename(args): return expression
The difference in the result (the only one I know of) is that the code and function objects get the generic name '<lambda>' instead of the more informative (in repr() output or tracebacks) 'somename'. I consider this a disadvantage.
In the absence of any compensating advantages (other than the trivial saving of 3 chars), I consider the def form to be the proper Python style to the point I think it should be at least recommended for the stdlib in the Programming Recommendations section of PEP 8.
There are currently uses of named lambdas at least in urllib2. This to me is a bad example for new Python programmers.
What do our style mavens think?
+1. -Brett
On Sat, 3 May 2008, Brett Cannon wrote:
On Sat, May 3, 2008 at 1:03 AM, Terry Reedy
wrote: Some people write somename = lambda args: expression instead of the more obvious (to most people) and, dare I say, standard def somename(args): return expression
The difference in the result (the only one I know of) is that the code and function objects get the generic name '<lambda>' instead of the more informative (in repr() output or tracebacks) 'somename'. I consider this a disadvantage.
In the absence of any compensating advantages (other than the trivial saving of 3 chars), I consider the def form to be the proper Python style to the point I think it should be at least recommended for the stdlib in the Programming Recommendations section of PEP 8.
There are currently uses of named lambdas at least in urllib2. This to me is a bad example for new Python programmers.
What do our style mavens think?
+1.
A superfluous +1 from me too, although I will mention that lists of lambdas have saved my butt more than a few times. -- Cheers, Leif
Terry Reedy wrote:
Some people write somename = lambda args: expression instead of the more obvious (to most people) and, dare I say, standard def somename(args): return expression
The difference in the result (the only one I know of) is that the code and function objects get the generic name '<lambda>' instead of the more informative (in repr() output or tracebacks) 'somename'. I consider this a disadvantage.
In the absence of any compensating advantages (other than the trivial saving of 3 chars), I consider the def form to be the proper Python style to the point I think it should be at least recommended for the stdlib in the Programming Recommendations section of PEP 8.
There are currently uses of named lambdas at least in urllib2. This to me is a bad example for new Python programmers.
What do our style mavens think?
I found only an example in my personal recent code: START = "<!-- *db-payload-start* -->" END = "<!-- *db-payload-end* -->" TITLEPATTERN = lambda s: "<title>%s</title>" % s this three are later used in a very few .find() and .replace() expressions in the same module. I suppose my point is that while I agree it should be discouraged and is really silly to do it for the few chars gain, it can be used to some effect in very rare cases.
Samuele Pedroni wrote:
I found only an example in my personal recent code:
START = "<!-- *db-payload-start* -->" END = "<!-- *db-payload-end* -->" TITLEPATTERN = lambda s: "<title>%s</title>" % s
this three are later used in a very few .find() and .replace() expressions in the same module. I suppose my point is that while I agree it should be discouraged and is really silly to do it for the few chars gain, it can be used to some effect in very rare cases.
The way that's written currently, I think I could *very* easily miss the fact that TITLEPATTERN is a callable while glancing over the code (and be very confused if I later saw it being called or passed as a callback). Converting to a def makes it obvious that one of these lines is not like the others: START = "<!-- *db-payload-start* -->" END = "<!-- *db-payload-end* -->" def TITLEPATTERN(s): return "<title>%s</title>" % s Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://www.boredomandlaziness.org
Nick Coghlan wrote:
Samuele Pedroni wrote:
I found only an example in my personal recent code:
START = "<!-- *db-payload-start* -->" END = "<!-- *db-payload-end* -->" TITLEPATTERN = lambda s: "<title>%s</title>" % s
this three are later used in a very few .find() and .replace() expressions in the same module. I suppose my point is that while I agree it should be discouraged and is really silly to do it for the few chars gain, it can be used to some effect in very rare cases.
The way that's written currently, I think I could *very* easily miss the fact that TITLEPATTERN is a callable while glancing over the code (and be very confused if I later saw it being called or passed as a callback).
confused? maybe, "very" seems an overstatement
On Sat, 3 May 2008 08:27:27 pm Nick Coghlan wrote:
Samuele Pedroni wrote:
I found only an example in my personal recent code:
START = "<!-- *db-payload-start* -->" END = "<!-- *db-payload-end* -->" TITLEPATTERN = lambda s: "<title>%s</title>" % s
this three are later used in a very few .find() and .replace() expressions in the same module. I suppose my point is that while I agree it should be discouraged and is really silly to do it for the few chars gain, it can be used to some effect in very rare cases.
The way that's written currently, I think I could *very* easily miss the fact that TITLEPATTERN is a callable while glancing over the code (and be very confused if I later saw it being called or passed as a callback).
I think you're exaggerating a tad here. Why would you be "very confused" when you see TITLEPATTERN() or foo(callback=TITLEPATTERN)? What else would TITLEPATTERN be but a callable when it's being used as a callable?
Converting to a def makes it obvious that one of these lines is not like the others:
Do you get confused by factory functions? (or for that matter callable class instances, types, etc.) TITLEPATTERN = factory(args) # note the lack of def ... lots of code ... foo(callback=TITLEPATTERN) # Note: TITLEPATTERN is a callable I think that if I argued that factory functions were bad because "I think I could *very* easily miss the fact that TITLEPATTERN is a callable while glancing over the code (and be very confused if I later saw it being called or passed as a callback)", most people would dismiss the concern and tell me it was my problem. It certainly isn't a good reason for discouraging factory functions, and I don't think it should be considered a good reason for discouraging lambdas. -- Steven D'Aprano
Steven D'Aprano
I think you're exaggerating a tad here. Why would you be "very confused" when you see TITLEPATTERN() or foo(callback=TITLEPATTERN)? What else would TITLEPATTERN be but a callable when it's being used as a callable?
The real problem is this example is not the fact that there is a lambda, but that the variable name doesn't reflect it is a callable. It is common practice to use verbs for callables, and nouns for non-callables. Thus I'd expect the variable to be called something like make_title_pattern rather than TITLEPATTERN (and what's with the ugly allcaps by the way?). Antoine.
Samuele Pedroni wrote:
I found only an example in my personal recent code:
START = "<!-- *db-payload-start* -->" END = "<!-- *db-payload-end* -->" TITLEPATTERN = lambda s: "<title>%s</title>" % s
this three are later used in a very few .find() and .replace() expressions in the same module. I suppose my point is that while I agree it should be discouraged and is really silly to do it for the few chars gain, it can be used to some effect in very rare cases.
i.e. anywhere you need a portable expression (as opposed to a portable set of statements). I have a feeling that if it were named 'expr' instead of 'lambda' we wouldn't be having this discussion. Robert Brewer fumanchu@aminus.org
Terry Reedy wrote:
Some people write somename = lambda args: expression instead of the more obvious (to most people) and, dare I say, standard def somename(args): return expression
Visually I find the second form very ugly. The colon indicates to me that a new line is expected, and breaking that expectation breaks my flow of code reading. I very *rarely* use lambdas in the form you show, but where you do I prefer them to the single line function. Michael Foord
The difference in the result (the only one I know of) is that the code and function objects get the generic name '<lambda>' instead of the more informative (in repr() output or tracebacks) 'somename'. I consider this a disadvantage.
In the absence of any compensating advantages (other than the trivial saving of 3 chars), I consider the def form to be the proper Python style to the point I think it should be at least recommended for the stdlib in the Programming Recommendations section of PEP 8.
There are currently uses of named lambdas at least in urllib2. This to me is a bad example for new Python programmers.
What do our style mavens think?
Terry Jan Reedy
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/fuzzyman%40voidspace.org.u...
[Terry Reedy]
Some people write somename = lambda args: expression instead of the more obvious (to most people) and, dare I say, standard def somename(args): return expression
Though def-statements are usually the best way to go, there are some reasonable cases where the first form reads better. I say leave it to the programmer to decide. Experience will quickly teach the def-statement is more flexible. Another thought is that I often give the advice that if a long-line becomes hard to read, then an easy solution is to pull-out an inner expression and give it a name. This is especially true when the intended purpose of the inner expression isn't obvious and giving it a name adds clarity. I would have to burden this advice with an admonition to go further and move the relevant code farther away from where it is used: for k,g in groupby(iterable, key=lambda r: (r[0].lower(), r[5].lower())): ... lastname_firstname = lambda r: (r[0].lower(), r[5].lower()) for k, g in groupby(iterable, key=lastname_firstname): ... That transformation adds clarity. Going further and creating a separate def-statement outside the current function would just move the relevant code farther away and impair readability. Also, I'm somewhat opposed to using PEP 8 in this way. Somehow, the PEPs recommendations seem to get occasionally interpreted as law. IMO, the PEP should be limited to things that have a real impact on code being maintained by multiple programmers. It should not grow into a general purpose set of situation independent prejudgments about which constructs should be favored over others (i.e. programmer x hates for-else so those should be avoided in favor of using flags or programmer y thinks it's uncool to have a return-statement anywhere but the end of a function).
What do our style mavens think?
-1 Raymond
On Sun, May 4, 2008 at 3:31 AM, Raymond Hettinger
for k,g in groupby(iterable, key=lambda r: (r[0].lower(), r[5].lower())): ... lastname_firstname = lambda r: (r[0].lower(), r[5].lower()) for k, g in groupby(iterable, key=lastname_firstname): ...
That transformation adds clarity. Going further and creating a separate def-statement outside the current function would just move the relevant code farther away and impair readability.
And that would be totally silly and uncalled for -- why ever would it be placed *outside the current function*?! What a straw-man...! Just do def last_first(r): return r[0].lower(), r[5].lower() for k, g in groupby(iterable, key=last_first): ... putting the def right where you now have the "<name> = lambda ..." of course! Alex
Raymond Hettinger wrote:
lastname_firstname = lambda r: (r[0].lower(), r[5].lower()) for k, g in groupby(iterable, key=lastname_firstname): ...
That transformation adds clarity. Going further and creating a separate def-statement outside the current function would just move the relevant code farther away and impair readability.
It doesn't have to be outside the function -- it can be in exactly the same place as the lambda assignment above. def lastname_firstname(r): return (r[0].lower(), r[5].lower()) for k, g in groupby(iterable, key=lastname_firstname): ... Maybe "def is an executable statement" is another thing people have a blind spot about? -- Greg
participants (22)
-
"Martin v. Löwis"
-
Alex Martelli
-
Antoine Pitrou
-
Boris Borcic
-
Brett Cannon
-
Christian Heimes
-
Georg Brandl
-
Greg Ewing
-
Guido van Rossum
-
Jeff Hall
-
Jesse Noller
-
Leif Walsh
-
Michael Foord
-
Mike Klaas
-
Nick Coghlan
-
Raymond Hettinger
-
Robert Brewer
-
Samuele Pedroni
-
Scott David Daniels
-
Steven
-
Steven D'Aprano
-
Terry Reedy