"Updating" lambda functions

O

Oliver Fromme

Hi,

I'm trying to write a Python function that parses
an expression and builds a function tree from it
(recursively).

During parsing, lambda functions for the the terms
and sub-expressions are constructed on the fly.
Now my problem is lazy evaluation. Or at least I
think it is. :)

I need to "update" a lambda function, like this:

fu = lambda x: x
...
fu = lambda x: fu(x) + 17
...
fu = lambda x: fu(x) * 3

Of course that doesn't work, because fu is resolved
when the lambda is called, not when it's defined, so
I'll run into an endless recursion.

My current solution is to define a helper function
which passes the lambda through its argument:

def add_17 (fu):
return lambda x: fu(x) + 17

def mul_3 (fu):
return lambda x: fu(x) * 3

fu = lambda x: x
...
fu = add_17(fu)
...
fu = mul_3(fu)

That works, but it strikes me as unclean and ugly.
Is there a better way to do it?

Best regards
Oliver
 
E

Elaine Jackson

| That works, but it strikes me as unclean and ugly.
| Is there a better way to do it?

I don't like it either. Consider this:
60
 
B

Bengt Richter

Hi,

I'm trying to write a Python function that parses
an expression and builds a function tree from it
(recursively).

During parsing, lambda functions for the the terms
and sub-expressions are constructed on the fly.
Now my problem is lazy evaluation. Or at least I
think it is. :)

I need to "update" a lambda function, like this:

fu = lambda x: x
...
fu = lambda x: fu(x) + 17
...
fu = lambda x: fu(x) * 3

Of course that doesn't work, because fu is resolved
when the lambda is called, not when it's defined, so
I'll run into an endless recursion.

My current solution is to define a helper function
which passes the lambda through its argument:

def add_17 (fu):
return lambda x: fu(x) + 17

def mul_3 (fu):
return lambda x: fu(x) * 3

fu = lambda x: x
...
fu = add_17(fu)
...
fu = mul_3(fu)

That works, but it strikes me as unclean and ugly.
Is there a better way to do it?

Best regards
Oliver

--
Oliver Fromme, Konrad-Celtis-Str. 72, 81369 Munich, Germany

``All that we see or seem is just a dream within a dream.''
(E. A. Poe)

You could exploit the way functions become bound methods, e.g.,
Traceback (most recent call last):
<bound method ?.<lambda> of <bound method ?.<lambda> of <function <lambda> at 0x008FD8B0>>>

or, you could make a magic function-composing object with magic composing properties,
exploiting the method-making mechanism in a different way, e.g.,
... def __setattr__(self, name, f):
... if not hasattr(self, name): self.__dict__[name] = [f]
... else: self.__dict__[name].append(f)
... def __getattribute__(self, name):
... if name == '__dict__': return object.__getattribute__(self, '__dict__')
... return type(self).__dict__['_xfuns'].__get__(
... object.__getattribute__(self,name))
... def _xfuns(flist, x):
... for f in flist: x = f(x)
... return x
... Traceback (most recent call last):
-3

All just to explore python's features, not to recommend specific uses ;-)

Regards,
Bengt Richter
 
T

Terry Reedy

Oliver Fromme said:
fu = lambda x: x
fu = lambda x: fu(x) + 17
etc

I am curious if there is any reason other that habit carried over from
other languages to not write the above as

def fu(x): return x
def fu(x): return fu(x) + 17
etc

Granted, the latter takes 2 more keystrokes, but the resulting object gets
a proper .name attribute. And, of course, the def form is required for a
multiline body anyway.

(Note: I am not asking about the use of lambda *within* an expression or as
a return value, but only the immediate name-binding of the supposedly
anonymous function where one does not want anonymity.)

Terry J. Reedy
 
E

Elaine Jackson

| I am curious if there is any reason other that habit carried over from
| other languages to not write the above as
|
| def fu(x): return x
| def fu(x): return fu(x) + 17
| etc

In my interpreter (IDLE 1.0 on Windows 98) it causes an infinite regress.
 
S

Steven Bethard

Elaine Jackson said:
"Terry Reedy" <tjreedy <at> udel.edu> wrote in message
<at> python.org...

| I am curious if there is any reason other that habit carried over from
| other languages to not write the above as
|
| def fu(x): return x
| def fu(x): return fu(x) + 17
| etc

In my interpreter (IDLE 1.0 on Windows 98) it causes an infinite regress.

Yes, it will, exactly as the lambda version would have. (And all the
solutions suggested to you for the lambda form are equally applicable to the
def form.) The question is why use the lambda form when you *do* want to bind
your function to a name? Basically,

f = lambda args: body

is equivalent to

def f(args): body

except that the def body is a set of statements (so you have to use 'return'),
and the lambda body is a single expression.

Not that it's coming any time soon, but Python 3000 is supposed to remove
lambda functions, so when you really *do* want to bind a function to a name
(like in your case here), it would probably be a good habit to get into to use
defs instead.

Steve
 
B

Bengt Richter

Yes, it will, exactly as the lambda version would have. (And all the
solutions suggested to you for the lambda form are equally applicable to the
def form.) The question is why use the lambda form when you *do* want to bind
your function to a name? Basically,

f = lambda args: body

is equivalent to

def f(args): body

except that the def body is a set of statements (so you have to use 'return'),
and the lambda body is a single expression.
Yes, but

obj.f = lambda args: body

is possible without an intermediate local binding of f that might clobber a previous f, as in

def f(args): body
obj.f = f
del f # if you want to clean up. But better save the old f in that case?

I'd rather use lambda.
Not that it's coming any time soon, but Python 3000 is supposed to remove
lambda functions, so when you really *do* want to bind a function to a name
(like in your case here), it would probably be a good habit to get into to use
defs instead.
Well, if lambda is removed (or not ;-), I hope an anonymous def expression is allowed,
so we can write

obj.f = def(args):
body
or

obj.f = def(args): body

or

obj.f = (
def(args):
body
) # at or to the left of the def column, for final dedent without special ')' processing.


(where def body indentation is referenced from wherever the def is)

Regards,
Bengt Richter
 
S

Steven Bethard

Bengt Richter said:
Yes, but

obj.f = lambda args: body

is possible without an intermediate local binding of f that might clobber a
previous f

Yeah, I probably should have been clear about that. If 'f' is really just a
name (as it was in my example) the two syntaxes I gave are equivalent. If 'f'
really isn't just a name, then you do still want an anonymous function. In
the OP's example though, 'f' really was just a name.
Well, if lambda is removed (or not , I hope an anonymous def expression is
allowed...

Well, it's come up a number of times (one of the more recent is
http://mail.python.org/pipermail/python-list/2004-June/226714.html), but it
doesn't seem like there was any agreement on (a) what it should look like, or
(b) why having such anonymous defs was such a gain over named defs. If you'd
like to champion a PEP about it... ;)

Steve
 
T

Terry Reedy

Bengt Richter said:
obj.f = lambda args: body

is possible without an intermediate local binding of f that might clobber
a previous f, as in

def f(args): body
obj.f = f
del f # if you want to clean up. But better save the old f in that
case?

I'd rather use lambda.

Thanks. I had not thought of this variation. Similar would be
seq[n] = lambda <whatever>

Of course, I *might* prefer being able to write

def obj.f(params): <etc> # and
def seq[n](params): <etc>

Since def is effectively a binding statement, name to function object (like
import, name to module), these seem not entirely unreasonable to me.

Terry J. Reedy
 
C

Clark C. Evans

What? is lambda is going away? Say it ain't so!

body
| > is equivalent to
| >def f(args): body

Not really -- the item above is _bad style_, people write,

def f(args):
body

| obj.f = lambda args: body

Or more commonly,

func(arg, lambda args: body)

| I'd rather use lambda.

No joke. For the common case above, which occurs _everywhere_
in my 'deferred execution' code, one would write:

def somerandomname(args):
body
func(arg, somerandomname)

So, you've taken something that is a perfectly clear one-liner and
converted it into a 3 line chunk of code with _zero_ added clarity,
in fact, I'd say you've dramatically reduced clarity by requiring
the a name be 'minted'. Ugly. Multiply this by 10x in one of my
source files and you've taken something perfectly readable and
turned it into maze of confusion. This _hides_ the true intent
rather than making it clear that the function is temporary thingy.

| >Not that it's coming any time soon, but Python 3000 is supposed to remove
| >lambda functions

Expect me to whine very loudly on a daily basis when Python 3000
becomes near. In fact, let the preemptive supplication begin.

| Well, if lambda is removed (or not ;-), I hope an anonymous def
| expression is allowed, so we can write
|
| obj.f = def(args):
| body
| or
|
| obj.f = def(args): body
|
| or
|
| obj.f = (
| def(args):
| body
| )

Ewww. How is this better than lambda? Let's keep lambda, no?

Clark

--
Clark C. Evans Prometheus Research, LLC.
http://www.prometheusresearch.com/
o office: +1.203.777.2550
~/ , mobile: +1.203.444.0557
//
(( Prometheus Research: Transforming Data Into Knowledge
\\ ,
\/ - Research Exchange Database
/\ - Survey & Assessment Technologies
` \ - Software Tools for Researchers
~ *
 
D

Dave Benjamin

What? is lambda is going away? Say it ain't so!

They keep threatening it, and it keeps not happening. In the meantime, we
can use this time to our advantage, preparaing our vocal chords for the
eventual screaming fits and wails of agonizing pain. ;)
| >Not that it's coming any time soon, but Python 3000 is supposed to remove
| >lambda functions

Expect me to whine very loudly on a daily basis when Python 3000
becomes near. In fact, let the preemptive supplication begin.

Since enough time has gone by since I last whined, let me just take this
opportunity to say, in a completely calm, diplomatic, and
non-confrontational way: "Ruby-style code blocks would be nice."

(o) Don't beg for code blocks again today
( ) Don't beg for code blocks again in the next three days
( ) Don't beg for code blocks again in the next week

[ OK ]
 
J

Jeff Shannon

Clark said:
No joke. For the common case above, which occurs _everywhere_
in my 'deferred execution' code, one would write:

def somerandomname(args):
body
func(arg, somerandomname)

So, you've taken something that is a perfectly clear one-liner and
converted it into a 3 line chunk of code with _zero_ added clarity,
in fact, I'd say you've dramatically reduced clarity by requiring
the a name be 'minted'. Ugly.

I don't agree. I *still* have to stop and think every time I see a
lamba -- they parse completely differently in my mind than anything else
in Python does, and they confuse me every time. Yes, defining a small
function requires two extra lines... but, y'know, it's not like my
editor is going to run out of paper. And I find that a well-chosen
name, even for a single-use thing like this, greatly adds clarity. To
my mind, calling this func_callback(), or some such descriptive name,
makes the intent *much* more clear than 'lambda' does.
Multiply this by 10x in one of my
source files and you've taken something perfectly readable and
turned it into maze of confusion. This _hides_ the true intent
rather than making it clear that the function is temporary thingy.

Only when one is already familiar with lambdas. I've gotten to the
point where I *can* understand them, but it's still a struggle. It
seems to me that the benefits of having lambda are outweighed by the
fair amount of extra mental space that they use up. It just strikes me
as too much of a special case to deserve special syntax that has
absolutely no parallel elsewhere in Python.
| Well, if lambda is removed (or not ;-), I hope an anonymous def
| expression is allowed, so we can write
|
| obj.f = def(args):
| body
| or
|
| obj.f = def(args): body
|
| or
|
| obj.f = (
| def(args):
| body
| )

Ewww. How is this better than lambda? Let's keep lambda, no?

I certainly agree that none of these examples strike me as less
troublesome than lambda. Indeed, the second one effectively *is* lambda
syntax, except with added parens and a name change. And the others both
scream out that there *will* be problems with indenting properly.

I remain unconvinced that the utility of anonymity is so great that
either special case is justified.

Jeff Shannon
Technician/Programmer
Credit International
 
V

Ville Vainio

Clark> def somerandomname(args):
Clark> body
Clark> func(arg, somerandomname)

Clark> So, you've taken something that is a perfectly clear
Clark> one-liner and converted it into a 3 line chunk of code with
Clark> _zero_ added clarity, in fact, I'd say you've dramatically
Clark> reduced clarity by requiring the a name be 'minted'. Ugly.

What does "minting" a name mean?

You can always do

def L(args): body

func(arg, L)

You can even make it a habit to always call it L.

Clark> Expect me to whine very loudly on a daily basis when Python
Clark> 3000 becomes near. In fact, let the preemptive
Clark> supplication begin.

Heh, I can already anticipate the whining around py3000. It will
probably be a test bed for hundreds of new voting methods and give
sociology students thesis-fodder for years.

Clark> Ewww. How is this better than lambda? Let's keep lambda,
Clark> no?

I agree. Lambda doesn't suck anymore, so it deserves to live.
 
C

Clark C. Evans

On Mon, Oct 11, 2004 at 10:54:05AM -0700, Jeff Shannon wrote:
| I don't agree. I *still* have to stop and think every time I see a
| lamba -- they parse completely differently in my mind than anything else
| in Python does, and they confuse me every time. Yes, defining a small
| function requires two extra lines... but, y'know, it's not like my
| editor is going to run out of paper. And I find that a well-chosen
| name, even for a single-use thing like this, greatly adds clarity. To
| my mind, calling this func_callback(), or some such descriptive name,
| makes the intent *much* more clear than 'lambda' does.

I beg to differ; and I'm talking about _my_ code, not yours.

| Only when one is already familiar with lambdas. I've gotten to the
| point where I *can* understand them, but it's still a struggle. It
| seems to me that the benefits of having lambda are outweighed by the
| fair amount of extra mental space that they use up. It just strikes me
| as too much of a special case to deserve special syntax that has
| absolutely no parallel elsewhere in Python.

If you don't like lambda -- don't use it. Just beacuse you are
unfamilar with a very helpful construct and are unwilling to learn
does not mean you should prevent others from continuing to enjoy
one of the more pleasant aspects of Python.

Kind Regards,

Clark
 
G

gabriele renzi

Dave Benjamin ha scritto:
Since enough time has gone by since I last whined, let me just take this
opportunity to say, in a completely calm, diplomatic, and
non-confrontational way: "Ruby-style code blocks would be nice."

(o) Don't beg for code blocks again today
( ) Don't beg for code blocks again in the next three days
( ) Don't beg for code blocks again in the next week

[ OK ]

do a b:
indentblock

would be uber cool, imho.
 
J

Jeff Shannon

Clark said:
On Mon, Oct 11, 2004 at 10:54:05AM -0700, Jeff Shannon wrote:
|
| .... It
| seems to me that the benefits of having lambda are outweighed by the
| fair amount of extra mental space that they use up. It just strikes me
| as too much of a special case to deserve special syntax that has
| absolutely no parallel elsewhere in Python.

If you don't like lambda -- don't use it. Just beacuse you are
unfamilar with a very helpful construct and are unwilling to learn
does not mean you should prevent others from continuing to enjoy
one of the more pleasant aspects of Python.

Except that one of the design principles of Python is that it being easy
to *read* is more important than being easy to write, with the
assumption that much of the code that one reads will be code written by
someone else. I do care how readable your code is, because (at least in
principle) someday I may need to maintain it. ("If you don't like X,
don't use it, but let others use it if they like" seems to be much more
Perlish than Pythonic, at least IMHO.)

Lambdas are hard to read, because they're significantly different,
syntactically, from any other construct in the language -- it's not that
I'm _unwilling_ to learn, it's that it is actively *difficult* to learn
because it doesn't fit well, conceptually, into the rest of the
language, so there's a mental impedance barrier that must be overcome.
In order to explain lambdas to someone who is not already familiar with
them, you have to explain first that it's kind of like a function def,
except that it uses totally different syntax (aren't function defs
supposed to use parens?), and you don't explicitly return anything even
though it *does* return a value, and oh yes, you can't actually use
statements because it has to be a single expression (and then you get to
explain the difference between statements and expressions, and explain
*why* there's a difference and that it really is a good thing)...
That's a lot of special treatment for those cases where there actually
might be a slight advantage to using an anonymous function, and "Special
cases aren't special enough to break the rules." Lambdas *do* break
many of Python's usual rules.

Jeff Shannon
Technician/Programmer
Credit International
 
C

Clark C. Evans

On Mon, Oct 11, 2004 at 11:58:44AM -0700, Jeff Shannon wrote:
| >If you don't like lambda -- don't use it. Just beacuse you are
| >unfamilar with a very helpful construct and are unwilling to learn
| >does not mean you should prevent others from continuing to enjoy
| >one of the more pleasant aspects of Python.
|
| Except that one of the design principles of Python is that it being easy
| to *read* is more important than being easy to write

Exactly! Lambdas make my code easy to read and therefore more
understandable. I don't use them beacuse they are easier to write,
I use them beacuse they make reviewing source code easier:

- they put simple expressions that are arguments right
where they are used

- they don't create random names that you have to worry
about name collision or finding something meaningful
(and not distracting)

- you are certain to know that the chunk of code is not
used anywhere else, that is, you can freely modify it

Lambdas are all about making code more maintainable.

| Lambdas are hard to read,

This is _your_ opinion; lots of other people disagree.

| because they're significantly different,
| syntactically, from any other construct in the language

This argument is just bogus. There are lots of things in Python
that are significantly different from each other:

- functions that return functoins, and hence can().be().chained()
- using expressions as function arguments
- list comprehensions
- *args and **kwargs
- overridable operators
- classes, meta-classes
- etc.

In any of these cases one _could_ of course, find a similar way
to do it with just a turning machine. But this isn't the point,
the point is to give special syntax to common things that have
specific meaning so that they are easily recognized.

Best,

Clark
 
G

gabriele renzi

Jeff Shannon ha scritto:

Let me say that all of this is in a big IMO block. Oh, and sorry for the
triple post, thunderbird got mad.
Except that one of the design principles of Python is that it being easy
to *read* is more important than being easy to write, with the
assumption that much of the code that one reads will be code written by
someone else. I do care how readable your code is, because (at least in
principle) someday I may need to maintain it. ("If you don't like X,
don't use it, but let others use it if they like" seems to be much more
Perlish than Pythonic, at least IMHO.)


I agree on the perlish thinking of 'some more feature you can avoid are
good'. But lambdas are a concept that can be (and actually is) used for
a lot of things where it is better than others.
Lambdas are hard to read, because they're significantly different,
syntactically, from any other construct in the language -- it's not that
I'm _unwilling_ to learn, it's that it is actively *difficult* to learn
because it doesn't fit well, conceptually, into the rest of the
language, so there's a mental impedance barrier that must be overcome.

IMO the problem is just that lambda is an onion (citing paul graham that
cites primo levi google for the explanation). It is a remnant of
academic computer science.

Would you like to have it like:
func arg1,arg2: arg1+arg2
?

Again, IMO the point is: once people explain this to you, would you find
hard it to understand or read a lambda once you find them again?
Is this different from the strangeness of array literals or generator
expression/LC ?
In order to explain lambdas to someone who is not already familiar with
them, you have to explain first that it's kind of like a function def,
except that it uses totally different syntax (aren't function defs
supposed to use parens?), and you don't explicitly return anything even
though it *does* return a value, and oh yes, you can't actually use
statements because it has to be a single expression (and then you get to
explain the difference between statements and expressions, and explain
*why* there's a difference and that it really is a good thing)...

then what you want is a better lambda. One where you can use return,
maybe, and where you can have statements and multiple expressions.
Don't throw away the baby with the bathwater.

That's a lot of special treatment for those cases where there actually
might be a slight advantage to using an anonymous function, and "Special
cases aren't special enough to break the rules." Lambdas *do* break
many of Python's usual rules.

Just because you're thinking of lambdas as special cases. Whenever a
case is very useful it is possible to break the rules. That's why there
are all those funny literals.
 
S

Steven Bethard

Jeff Shannon said:
Lambdas are hard to read, because they're significantly different,
syntactically, from any other construct in the language

Yes, they are different (summarizing your points):
* no parens around argument list
* returns a value without the return statement
* contains a single expression, not a sequence of statements

Of course, comparing something like the new decorator syntax to the older
equivalent will also point out a construct that's "significantly different,
syntactically, from any other construct in the language":

@d1
@d2
def f():
pass

as opposed to

def f():
pass
f = d1(d2(f))

Some points (in parallel with yours, as much as possible):
* no parens, but functions are called
* rebinds a name without an assignment statement[1]
* appear as expressions, but act like statements
* appear before a def, but are applied after

I'd contend that lambda syntax is much more in-line with the rest of Python
than decorator syntax. Not that I'm suggesting we get rid of decorator
syntax -- I've already found it useful on a number of occasions. I just
wanted to point out that, all things considered, lambdas are probably more
consistent with Python than decorators are.

Steve

[1] Actually, I believe the function is not bound to a name until after the
decorators are applied, but I don't think it's completely unreasonable to talk
of this as a name rebinding.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,125
Latest member
VinayKumar Nevatia_
Top