"Updating" lambda functions

J

Jeff Shannon

gabriele said:
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.


But because of Python's line- and indentation-based syntax, doing all of
that on a single line is... um... awkward at best, to put it mildly.
And once you make a lambda multiline, then you lose most of the point of
it -- at least, as far as I understand what the point is (having an
in-line, anonymous callable). Once you allow statements and multiple
expressions, all you're gaining is anonymity, which seems like a pretty
paltry benefit to me.
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.


I agree that, if a case is *very* useful, it is possible to break the
rules. List comprehensions, for example, break some of the rules, but
they are indeed very useful, so the rule-breakage is more forgiveable.

Maybe I'm just ignorant or behind the times, but I still haven't seen a
real argument as to *why* lambdas are so useful. There's some
assertions about how avoiding giving something a name makes things
clearer, which I disagree with. ('Explicit is better than implicit.' I
don't see how 'no name' makes the purpose of a code segment clearer than
'some meaningfully descriptive name', no matter how many times it's
asserted.) There's complaints that it takes a whole two extra lines to
type a proper function def, as opposed to being able to use lambdas
inline... but again, I'd claim that with a properly named function, the
intent at point-of-use will be quite clear and the cost of two extra
lines of code is minimal. (I also tend to break complex expressions
into multiple steps to increase clarity -- packing as much as possible
into a single line doesn't strike me as all that desirable.) There's
complaints about polluting the namespace... but ISTM that it's not
*that* hard to come up with uniquely descriptive names. Lambdas may
once have had some utility in capturing and tinkering with the scoping
of names, but that became moot with the introduction of nested scopes
'way back when.

I understand that lambdas are very popular in other programming
languages (such as Lisp). But Python is not those languages, and which
constructs are useful may well be different. I don't know enough Lisp
to judge how helpful lambdas are there; I do know enough Python to
believe that I should be able to see the advantages if they were as
wonderful as their proponents say. My suspicion is that all of the
Python users who like lambdas originally discovered them in other
languages and are comfortable with them from that environment, but those
who have no previous exposure to lambdas tend to be unimpressed (at
best) by Python's take on them. This renders them, IMO, in the same
category as the ternary operator that's continually proposed by converts
from, say, C/C++ -- a feature whose usability is much greater in other
languages than in Python, and whose inclusion would only satisfy those
familiar with the feature from those other languages. The only
difference between the two features, IMO, is that someone managed to
talk Guido into including lambdas (which he reportedly regrets), and
nobody managed to talk him into including the ternary operator.

Jeff Shannon
Technician/Programmer
Credit International
 
B

Bengt Richter

What? is lambda is going away? Say it ain't so!
I didn't write the following, I replied to it. Note the extra quoting level.
You are quoting Steven Bethard. See
http://groups.google.com/groups?hl=en&lr=&[email protected]
;-)
| >f = lambda args: body
| > is equivalent to
| >def f(args): body
It really should be
f = lambda args: expr
is equivalent to
def f(args): return expr
except for little details like f.__name__ and perhaps vestigial unexecuted
byte code in the def version, until someone thinks it's worth the bother to optimize out.
Not really -- the item above is _bad style_, people write,

def f(args):
body

| obj.f = lambda args: body

Or more commonly,
commonly compared to what? obj.f = ... ?
func(arg, lambda args: body)

| I'd rather use lambda.
That line I wrote, though the context is snipped ;-)
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 Bengt]
| >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.
[Bengt]
| 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?
Sure, lambda is fine, but it doesn't allow statements, so something
like def is needed. Just dropping the def name and allowing the
def statement to be an expression seemed an easy step, since the
name is basically the only difference.

As seen above, finding an indentation style that is easy to read is
a challeng, especially if the anonymous def is a middle argument to
a functions call, e.g.,

func(arg1, (def(x): print x), arg3)

much as with lambda, you may need parentheses to show where the expression ends.
For a more complex def, we get into multiple lines in the arg list, e.g.,
expanded,

func(
arg1, # use a new line to get consistent indenting of arg list items
(def(x, base=10):
"""even anonymous defs could have doc strings"""
return int(x+'0', base) # weird function
),
arg3
)

or, more compactly,

func(arg1,
def(x, base=10):
"""even anonymous defs could have doc strings"""
return int(x+'0', base) # weird function
,arg3)

It's a tough style problem. But what would you do with lambda, given that
we don't have lots of insignificant silly parentheses?

Regards,
Bengt Richter
 
D

Dave Benjamin

But because of Python's line- and indentation-based syntax, doing all of
that on a single line is... um... awkward at best, to put it mildly.

This is true. I think that Ruby's code block syntax offers a workable
alternative. Many will dispute this, saying it's too ugly, but this is
subjective and not based on any technical reasons. Here is what I've
proposed in the past:

def with_open_file(filename, proc):
f = open(filename)
try:
proc(f)
finally:
f.close()

with_open_file('data.txt', {|f|
for line in f:
print line
})

This is nearly identical to Ruby's syntax, except that instead of creating
an object with a call method, it creates a callable.
And once you make a lambda multiline, then you lose most of the point of
it -- at least, as far as I understand what the point is (having an
in-line, anonymous callable). Once you allow statements and multiple
expressions, all you're gaining is anonymity, which seems like a pretty
paltry benefit to me.

It's not so much the anonymity that matters, it's the ability to use them as
expressions. It allows you to create your own control structures without
disrupting the logical flow of your program. For instance, right now in
Python you'd have to write the above like this:

def doit(f):
for line in f:
print line

with_open_file('data.txt', doit)

To me, this reads, "When I say 'doit', I mean iterate through each line in
some given object 'f', and print that line. Now, with the open file, 'doit'."
Whereas, in the previous example, I'm saying, "With the open file, for each
line in the file, print the line." The difference is subtle, perhaps, but
the need to define a named function beforehand rearranges my code in a way
that I'm not particularly fond of.

Another example is the "after" procedure. If you're familiar with Tcl, you
may recognize the following idiom:

after(10, lambda: sprite.move(0, 5))

In an (imaginary) event-driven framework, this would wait 10 seconds before
moving "sprite" down 5 pixels. You might say that this could easily be
rewritten with a def, and you're right:

def doit():
sprite.move(0, 5)
after(10, doit)

Now, imagine you are setting up an animation this way:

after(10, lambda: sprite.move(0, 5))
after(15, lambda: sprite2.rotate(30))
after(20, lambda: sprite.scale(120, 120))
after(22, lambda: sprite2.move(50, 50))
after(22, lambda: sound1.play())
after(23, lambda: sprite.move(0, 0))
after(26, lambda: sound1.stop())

Imagine what happens when each one of these lambdas turns into a two-line
def. You could group the "def"s together, perhaps, but then you'd have to
give them all names like "move_sprite_0_5", which is totally redundant.
There are other ways to skin this cat, like switching to a more data-driven
model, but this is a practical use of anonymous functions; I do this kind of
thing all the time in JavaScript and ActionScript, which allow inline
anonymous functions.
I agree that, if a case is *very* useful, it is possible to break the
rules. List comprehensions, for example, break some of the rules, but
they are indeed very useful, so the rule-breakage is more forgiveable.

As was pointed out already in this thread, decorators break many of the same
rules. So far, I find anonymous functions much more useful than decorators.
The only problem is finding a suitable syntax, and I will admit this is
indeed a problem.
Maybe I'm just ignorant or behind the times, but I still haven't seen a
real argument as to *why* lambdas are so useful. There's some
assertions about how avoiding giving something a name makes things
clearer, which I disagree with. ('Explicit is better than implicit.' I
don't see how 'no name' makes the purpose of a code segment clearer than
'some meaningfully descriptive name', no matter how many times it's
asserted.)

In that case, why stop at functions? Why not make all intermediate values
have mandatory names? Why not ban this:

c = math.sqrt(a * a + b * b)

And require instead:

a2 = a * a
b2 = b * b
tmp = a2 + b2
c = math.sqrt(tmp)
There's complaints that it takes a whole two extra lines to
type a proper function def, as opposed to being able to use lambdas
inline... but again, I'd claim that with a properly named function, the
intent at point-of-use will be quite clear and the cost of two extra
lines of code is minimal. (I also tend to break complex expressions
into multiple steps to increase clarity -- packing as much as possible
into a single line doesn't strike me as all that desirable.) There's
complaints about polluting the namespace... but ISTM that it's not
*that* hard to come up with uniquely descriptive names. Lambdas may
once have had some utility in capturing and tinkering with the scoping
of names, but that became moot with the introduction of nested scopes
'way back when.

I understand that lambdas are very popular in other programming
languages (such as Lisp). But Python is not those languages, and which
constructs are useful may well be different. I don't know enough Lisp
to judge how helpful lambdas are there; I do know enough Python to
believe that I should be able to see the advantages if they were as
wonderful as their proponents say.

Lisp is not the only language that benefits from lambdas. Other languages
include JavaScript/ActionScript, C# (anonymous delegates), Java (anonymous
inner classes -- a poor substitute), Ruby, Tcl, Perl, and OCaml. They are
used in GUI callbacks, iteration patterns, flow control, data processing,
and in general any function or procedure that needs parts of its logic to be
parameterized. Only one of the aforementioned languages, OCaml, is
considered to be a functional language like Lisp or Scheme.
My suspicion is that all of the
Python users who like lambdas originally discovered them in other
languages and are comfortable with them from that environment, but those
who have no previous exposure to lambdas tend to be unimpressed (at
best) by Python's take on them. This renders them, IMO, in the same
category as the ternary operator that's continually proposed by converts
from, say, C/C++ -- a feature whose usability is much greater in other
languages than in Python, and whose inclusion would only satisfy those
familiar with the feature from those other languages. The only
difference between the two features, IMO, is that someone managed to
talk Guido into including lambdas (which he reportedly regrets), and
nobody managed to talk him into including the ternary operator.

I actually discovered lambdas in Python first (well, technically Tcl, but I
didn't know it at the time), and since then I have done a lot of programming
in Python. In fact, it would be safe to say that Python biases my use of
other languages to a greater degree than any other language biases my use of
Python. I don't use lambdas very often, but their use does come up, and I
would rather see them become more powerful (or see code blocks added to the
language) than have them be removed entirely. I'd like to see a ternary
operator too. Guido would have probably added one by now, but nobody could
agree on which syntax would be most "Pythonic". The same fate, I fear, is in
store for any sufficiently advanced anonymous function syntax in Python.

(Yet, somehow, decorators slipped through, even though nobody agreeed on a
syntax for that either. I don't have a rational explanation for that...)
 
S

Steven Bethard

Dave Benjamin said:
after(10, lambda: sprite.move(0, 5))
after(15, lambda: sprite2.rotate(30))
after(20, lambda: sprite.scale(120, 120))
after(22, lambda: sprite2.move(50, 50))
after(22, lambda: sound1.play())
after(23, lambda: sprite.move(0, 0))
after(26, lambda: sound1.stop())

Unfortunately, your "after" function is probably provided by your framework,
but if that framework was written a little more Python-friendly, the after
function would work like unittest.TestCase.assertRaises, e.g.

def after(sec, func, *args, **kwds):
# wait sec seconds
...
# call func
func(*args, **kwds)

This would let you write the code above as:

after(10, sprite.move, 0, 5)
after(15, sprite2.rotate, 30)
after(20, sprite.scale, 120, 120)
after(22, sprite2.move, 50, 50)
after(22, sound1.play)
after(23, sprite.move, 0, 0)
after(26, sound1.stop)

which is actually slightly more concise (character-wise) than the lambda code,
and doesn't force you to create a new lambda function to do something someone
already created a function for.

Again, I realize that in many cases having functions written like this is not
possible because the functions are defined by a framework, not the coder, but
if you happen to be one of the ones *writing* the framework, you can take
advantage of Python's *args and **kwds syntax to make this kind of thing
easier.

Steve
 
J

Jeff Shannon

Dave said:
Another example is the "after" procedure. If you're familiar with Tcl, you
may recognize the following idiom:

after(10, lambda: sprite.move(0, 5))

In an (imaginary) event-driven framework, this would wait 10 seconds before
moving "sprite" down 5 pixels. You might say that this could easily be
rewritten with a def, and you're right:

def doit():
sprite.move(0, 5)
after(10, doit)

Now, imagine you are setting up an animation this way:

after(10, lambda: sprite.move(0, 5))
after(15, lambda: sprite2.rotate(30))
after(20, lambda: sprite.scale(120, 120))
after(22, lambda: sprite2.move(50, 50))
after(22, lambda: sound1.play())
after(23, lambda: sprite.move(0, 0))
after(26, lambda: sound1.stop())

In this case, I'd redefine after to be:

def after(timeout, func, *args, **kwargs):
# whatever needs to be done to delay the call, then...
func(*args, **kwargs)

Then we can do the animation as:

after(10, sprite.move, 0, 5)
after(15, sprite2.rotate, 30)
after(20, sprite.scale, 120, 120)
# ...

I find this to read slightly better, and the implementation requires one
less level of indirection. I'll admit that I haven't explored much in
the area of function currying and closures, so there *may* be ways in
which using lambda is preferable to using a generic variable-argument
closure-returning function, but at least in the cases that spring to my
mind, lambda's advantage is slim at best.
As was pointed out already in this thread, decorators break many of the same
rules. So far, I find anonymous functions much more useful than decorators.
The only problem is finding a suitable syntax, and I will admit this is
indeed a problem.

And I'm not very happy with the decorator syntax either, to be honest.
Still, from the examples that cropped up during the Great Decorator
Syntax Debate (tm), it seems to me that, even though *I* don't
particularly need them, the potential benefits of decorators are greater
than the potential benefits of lambda. That is, I can see things that
can be done with user-defined descriptors that are difficult to do any
other way, whereas from what I've seen many/most uses of lambda can be
re-cast to use normal functions without too much pain. This provides a
bit more justification for having special syntax for user-defined
descriptors (i.e. decorators), though to be honest I'm not terribly
happy with the chosen syntax. Of course, this is all theoretical, since
at this point I've had no call to use either descriptors or lambdas...
In that case, why stop at functions? Why not make all intermediate values
have mandatory names? Why not ban this:

c = math.sqrt(a * a + b * b)

And require instead:

a2 = a * a
b2 = b * b
tmp = a2 + b2
c = math.sqrt(tmp)

Intermediate anonymous values make sense at a certain level of
granularity but not at all levels. Practicality beats purity.

On the other hand, I'd never write your first example -- I'd be
explicity about the grouping with extra parens.

c = math.sqrt( (a*a) + (b*b) )

It's not syntactically necessary, because it's following standard
operator precedence, but it scans much more quickly for me.

Indeed, maybe that's what this is all about. To my mind, when I see a
lambda, I already have to stop scanning, push a level on my mental
stack, figure out what the heck is going on with the lambda and what
it's going to return, and then pop back to the line in progress. In
contrast, when I'm scanning something using a (descriptively) named
function, the name should tell me enough of the purpose of the function
that I don't need to pause to figure it out. Thus, it's much quicker
for me to scan a reference to a named function than to scan a lambda
definition.

Lisp is not the only language that benefits from lambdas. Other languages
include JavaScript/ActionScript, C# (anonymous delegates), Java (anonymous
inner classes -- a poor substitute), Ruby, Tcl, Perl, and OCaml. They are
used in GUI callbacks, iteration patterns, flow control, data processing,
and in general any function or procedure that needs parts of its logic to be
parameterized. Only one of the aforementioned languages, OCaml, is
considered to be a functional language like Lisp or Scheme.

ISTM that many of these uses can be accomplished by using named
functions with variable arguments. I'll admit that I'm no language
expert, and TBH haven't used any of those languages. But my impression
is that the use of (named) function references, dynamic typing, and
convenient variable argument syntax can acheive most of the benefits
that are touted for lambdas.
(Yet, somehow, decorators slipped through, even though nobody agreeed on a
syntax for that either. I don't have a rational explanation for that...)

Nor do I ..... *sigh*

Jeff Shannon
Technician/Programmer
Credit International
 
D

Dave Benjamin

Unfortunately, your "after" function is probably provided by your framework,
but if that framework was written a little more Python-friendly, the after
function would work like unittest.TestCase.assertRaises, e.g.

def after(sec, func, *args, **kwds):
# wait sec seconds
...
# call func
func(*args, **kwds)

This would let you write the code above as:

after(10, sprite.move, 0, 5)
after(15, sprite2.rotate, 30)
after(20, sprite.scale, 120, 120)
after(22, sprite2.move, 50, 50)
after(22, sound1.play)
after(23, sprite.move, 0, 0)
after(26, sound1.stop)

which is actually slightly more concise (character-wise) than the lambda
code, and doesn't force you to create a new lambda function to do
something someone already created a function for.

Ahh, what clever solutions dynamic typing can afford. =) Very nice.
Again, I realize that in many cases having functions written like this is
not possible because the functions are defined by a framework, not the
coder, but if you happen to be one of the ones *writing* the framework,
you can take advantage of Python's *args and **kwds syntax to make this
kind of thing easier.

Even if modifying the framework function is not an option, you can still
accomplish similar results with an argument-binding function:

def bind(func, *args, **kwds):
return lambda: func(*args, **kwds)

after(10, bind(sprite.move, 0, 5))
after(15, bind(sprite2.rotate, 30))
after(20, bind(sprite.scale, 120, 120))
....

Or, in the "more readable" Python3k-enforced style:

def bind(func, *args, **kwds):
def doit():
return func(*args, **kwds)
return doit

after(10, bind(sprite.move, 0, 5))
....

(sorry, couldn't resist <g>)
 
D

Dave Benjamin

In this case, I'd redefine after to be:

def after(timeout, func, *args, **kwargs):
# whatever needs to be done to delay the call, then...
func(*args, **kwargs)

Apparently, you're not the only one. ;)
I find this to read slightly better, and the implementation requires one
less level of indirection. I'll admit that I haven't explored much in
the area of function currying and closures, so there *may* be ways in
which using lambda is preferable to using a generic variable-argument
closure-returning function, but at least in the cases that spring to my
mind, lambda's advantage is slim at best.

Python has many features that can delay evaluation and factor out
repetition, and this can largely explain why it's not so much of a nuisance
that it lacks a more powerful closure construct. For instance, on the dev
list, as quickly as the new "sort(key=lambda x: x[1])" idiom was introduced,
people started hunting for ways to squash the lambda, the winners being
"operator.attrgetter()" and "operator.itemgetter()". It is very likely that
anything you can do with a "lambda" you can also do using other features of
Python. Still, I think it's useful to note that the lambda version was the
first to be discussed, and the search for alternatives was in part motivated
by the threat of lambda's future demise. As long as lambda is there, people
will still use it for certain tasks, and sorting seems to be one of those
tasks.

The most convincing argument for (more powerful) lambdas over named
functions is in the design of custom control structures. For example, let's
say you wanted to define a do-while loop in Python. You could do it like this:

def do_while(proc, test):
while True:
proc()
if not test():
break

i = 0
def print_and_increment_i():
global i
print i
i += 1
def while_i_lt_10():
return i < 10
do_while(print_and_increment_i, while_i_lt_10)

With code blocks, you could implement something like this instead:

i = 0
do({||
print i
i += 1
}, while={||
return i < 10
})

As I write this, I feel a bit embarrassed; neither is really all that
readable, to be honest. But I'm going to post it anyway because I think it
illustrates my basic point, which is that the ability to use inline
functions allows you to implement control structures that would otherwise be
awkward and out-of-order. Real-world uses for custom control structures are
often application-specific and don't make much sense out of context. Say
you're working within a framework where you need to manage acquiring locks
and opening and closing resources:

lock.open({||
resource.acquire({|res|
res.dilly()
res.dally()
})
})

This would ensure that the lock gets closed even if the resource cannot be
acquired, and if everything works out, the resource gets released first, and
then the lock gets closed. The alternative people keep proposing would
result in code like this:

def do_while_resource_acquired(res):
res.dilly()
res.dally()

def do_while_lock_open():
resource.acquire(do_while_resource_acquired)

lock.open(do_while_lock_open)

Notice how the code now reads backwards?
And I'm not very happy with the decorator syntax either, to be honest.

I'm not really convinced that their usefulness demands syntax extension. On
the other hand, I've seen concrete examples in Ruby and other languages that
demonstrate the usefulness of code blocks, and in those cases, I think
syntax extension is worthwhile. But we all have different projects with
different needs, so one (wo)man's syntax extension is another's ugly wart.

Without macros, it's hard to please everyone. And with macros, it's hard to
please everyone. ;)
Intermediate anonymous values make sense at a certain level of
granularity but not at all levels. Practicality beats purity.

And one (wo)man's practicality is another's impurity.
On the other hand, I'd never write your first example -- I'd be
explicity about the grouping with extra parens.

c = math.sqrt( (a*a) + (b*b) )

It's not syntactically necessary, because it's following standard
operator precedence, but it scans much more quickly for me.

Indeed, maybe that's what this is all about. To my mind, when I see a
lambda, I already have to stop scanning, push a level on my mental
stack, figure out what the heck is going on with the lambda and what
it's going to return, and then pop back to the line in progress. In
contrast, when I'm scanning something using a (descriptively) named
function, the name should tell me enough of the purpose of the function
that I don't need to pause to figure it out. Thus, it's much quicker
for me to scan a reference to a named function than to scan a lambda
definition.

Yes, I can understand and sympathize with this viewpoint.
ISTM that many of these uses can be accomplished by using named
functions with variable arguments. I'll admit that I'm no language
expert, and TBH haven't used any of those languages. But my impression
is that the use of (named) function references, dynamic typing, and
convenient variable argument syntax can acheive most of the benefits
that are touted for lambdas.

And the use of wrenches, pliers, and mallets can achieve most of the
benefits that are touted for hammers. All of which happen to be objects. ;)
Nor do I ..... *sigh*

*coughjavacough*
 
B

Bengt Richter

This is true. I think that Ruby's code block syntax offers a workable
alternative. Many will dispute this, saying it's too ugly, but this is
subjective and not based on any technical reasons. Here is what I've
proposed in the past:

def with_open_file(filename, proc):
f = open(filename)
try:
proc(f)
finally:
f.close()

with_open_file('data.txt', {|f|
for line in f:
print line
})

This is nearly identical to Ruby's syntax, except that instead of creating
an object with a call method, it creates a callable.
How about extending lambda? E.g.,

with_open_file('data.txt', lambda f:<
for line in f:
print line

I.e., the first non-white-space after the initial ':<' defines suite indentation,
and a corresponding (to allow nesting) '>:' closes the lambda body (without necessarily
having to be out-dented). Hence you could do a one liner for the above example:

with_open_file('data.txt', lambda f:< for line in f: print line >:)

IMO, if you are familiar with lambda,

lambda f:< ... >:

is less of a jump than

{|f| ... }

What did I forget? ;-)

Obviously
lambda f:expr
can also be spelled
lambda f: said:
And once you make a lambda multiline, then you lose most of the point of
it -- at least, as far as I understand what the point is (having an
in-line, anonymous callable). Once you allow statements and multiple
expressions, all you're gaining is anonymity, which seems like a pretty
paltry benefit to me.

It's not so much the anonymity that matters, it's the ability to use them as
expressions. It allows you to create your own control structures without
disrupting the logical flow of your program. For instance, right now in
Python you'd have to write the above like this:

def doit(f):
for line in f:
print line

with_open_file('data.txt', doit)

To me, this reads, "When I say 'doit', I mean iterate through each line in
some given object 'f', and print that line. Now, with the open file, 'doit'."
Whereas, in the previous example, I'm saying, "With the open file, for each
line in the file, print the line." The difference is subtle, perhaps, but
the need to define a named function beforehand rearranges my code in a way
that I'm not particularly fond of. I agree.
[...]
I actually discovered lambdas in Python first (well, technically Tcl, but I
didn't know it at the time), and since then I have done a lot of programming
in Python. In fact, it would be safe to say that Python biases my use of
other languages to a greater degree than any other language biases my use of
Python. I don't use lambdas very often, but their use does come up, and I
would rather see them become more powerful (or see code blocks added to the
language) than have them be removed entirely. I'd like to see a ternary
operator too. Guido would have probably added one by now, but nobody could
agree on which syntax would be most "Pythonic". The same fate, I fear, is in
store for any sufficiently advanced anonymous function syntax in Python.

(Yet, somehow, decorators slipped through, even though nobody agreeed on a
syntax for that either. I don't have a rational explanation for that...)

Maybe we can piggyback on that ;-)

@lambda f:<
f.__name__ += '_decorated_by_an_extended_lambda'
return f >:
def foo(): pass

Regards,
Bengt Richter
 
P

Paul Rubin

Dave Benjamin said:
that it lacks a more powerful closure construct. For instance, on the dev
list, as quickly as the new "sort(key=lambda x: x[1])" idiom was introduced,
people started hunting for ways to squash the lambda, the winners being
"operator.attrgetter()" and "operator.itemgetter()".

But why would you want to need to remember such obscure functions? I
never heard of any of those. Maybe they should be eliminated instead of
lambda. There should be one obvious way to do it, and lambda suffices.
 
S

Steven Bethard

Paul Rubin said:
But why would you want to need to remember such obscure functions? I
never heard of any of those.

Couldn't tell if this was a joke or not, so in case it wasn't, attrgetter and
itemgetter are being introduced in Python 2.4, I believe as a result of the
sort(key=...) and sorted(key=...) discussions.
Maybe they should be eliminated instead of
lambda. There should be one obvious way to do it, and lambda suffices.

This is the part that really sounded like a joke, but in case it wasn't...

I could write a sort function every time I wanted to sort a list, but why not
use the one that comes builtin with Python lists? I could write a strip
function to remove whitespace from the ends of a string, but why not use the
one that comes builtin with Python strs? Likewise, I could write a (lambda)
function every time I wanted to select an item by index, e.g.

lambda x: x[1]

but if Python has already defined one for me, why would I define it again?

Steve
 
B

Bengt Richter

]
Just want to say this isn't my latest idea ;-) See below:
(the first non-white-space after the opening ':<' determines the suite indentation level,
and the matching >: ends the suite (without necessarily being outdented or on a separate line).
obj.f = lambda args:<
body
or

obj.f = lambda args:<
body >:

obj.f = lambda args: said:
Sure, lambda is fine, but it doesn't allow statements, so something
like def is needed. Just dropping the def name and allowing the
def statement to be an expression seemed an easy step, since the
name is basically the only difference.
I had second thoughts ;-)
As seen above, finding an indentation style that is easy to read is
a challeng, especially if the anonymous def is a middle argument to
a functions call, e.g.,

func(arg1, (def(x): print x), arg3)

much better (IMO) now:

func(arg1 said:
much as with lambda, you may need parentheses to show where the expression ends.
For a more complex def, we get into multiple lines in the arg list, e.g.,
expanded,

func(
arg1, # use a new line to get consistent indenting of arg list items
(def(x, base=10):
"""even anonymous defs could have doc strings"""
return int(x+'0', base) # weird function
),
arg3
)


func(
arg1, # use a new line to get consistent indenting of arg list items
lambda x, base=10:<
"""even anonymous lambdas could have doc strings"""
return int(x+'0', base) # weird function
arg3
)
or, more compactly,

func(arg1,
def(x, base=10):
"""even anonymous defs could have doc strings"""
return int(x+'0', base) # weird function
,arg3)

func(arg1,
lambda x, base=10:<
"""even anonymous lambdas could have doc strings"""
return int(x+'0', base) >:, # weird function
arg3)

One-liner:

It's a tough style problem. But what would you do with lambda, given that
we don't have lots of insignificant silly parentheses?

I guess I took a stab at answering my own question ;-)

Regards,
Bengt Richter
 
A

Antoon Pardon

Op 2004-10-11 said:
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

I didn't find them so. On the other hand I find having to come up
with a name for a function can be very inconvenient and not worth
the trouble. If python wants functions to be full fledged objects,
is needs some way to have unnamed functions, just as you can have
unnamed lists, numbers, instances etc.

Can you imaging the protest, from people if it would be decide
that no unnamed entities van be used. If you want to use a number
or a list, as an argument you first have to name it and then use
the name as argument. Well the reason for having anonymous numbers
and lists is the same reason for having anonymous functions.

-- 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?)

The problem is IMO that python uses two different kinds of ways to
assign an object to a name. You have the assignment and you have the
class and def statements. I would consider de class and def statements
the odd man out, because they combine the construcion of the object
with naming it, where normally the two are seperated.
 
A

Antoon Pardon

Op 2004-10-11 said:
But because of Python's line- and indentation-based syntax, doing all of
that on a single line is... um... awkward at best, to put it mildly.

Which is one of the reasons I think the indentation-based syntax was
a mistake. If the syntax becomes an argument against a construct
in the language, something is wrong with the syntax IMO.
 
C

Clark C. Evans

| > gabriele renzi wrote:
| >> 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.
| >
| > But because of Python's line- and indentation-based syntax, doing all of
| > that on a single line is... um... awkward at best, to put it mildly.
|
| Which is one of the reasons I think the indentation-based syntax was
| a mistake. If the syntax becomes an argument against a construct
| in the language, something is wrong with the syntax IMO.

Indentation based structure is a godsend; a divine insight if you may.
Python is much much better for it. However, just beacuse it can use
indentation, doesn't mean that indentation should be mandated for every
case. Python uses {} and [] to scope dict and list items, but this does
not mean that a indentation based version of this wouldn't be welcome.
In general, indentation is great for "outer-structure" that is,
delimiting large code blocks. While delimiter based scoping is good
for inner structures, small blocks of code. It should not be an
either/or thing, one should properly have the option of using either
option depending upon which style brings the most clarity.

Cheers,

Clark
 
J

Jeff Shannon

Antoon said:
I didn't find them so. On the other hand I find having to come up
with a name for a function can be very inconvenient and not worth
the trouble. If python wants functions to be full fledged objects,
is needs some way to have unnamed functions, just as you can have
unnamed lists, numbers, instances etc.

Can you imaging the protest, from people if it would be decide
that no unnamed entities van be used. If you want to use a number
or a list, as an argument you first have to name it and then use
the name as argument. Well the reason for having anonymous numbers
and lists is the same reason for having anonymous functions.

Functions are at a different level of granularity than numbers and
lists. Anonymity makes sense for numbers and lists; it makes less sense
for collections of numbers and lists; and it makes still less sense for
organized collections of numbers, lists, and operations thereon, which
are structured in a meaningful way to express some (part of an)
algorithm. Similarly, I don't expect each line of code to have an
individual name, but once I collect lines of code into a file, I
certainly *do* expect to name that file, even if the file is only one or
two lines long.

Jeff Shannon
Technician/Programmer
Credit International
 
A

Antoon Pardon

Op 2004-10-12 said:
Functions are at a different level of granularity than numbers and
lists. Anonymity makes sense for numbers and lists; it makes less sense
for collections of numbers and lists; and it makes still less sense for
organized collections of numbers, lists, and operations thereon, which
are structured in a meaningful way to express some (part of an)
algorithm.

I find it better to let the coder decide what makes sense in his program
and what not.
Similarly, I don't expect each line of code to have an
individual name, but once I collect lines of code into a file, I
certainly *do* expect to name that file, even if the file is only one or
two lines long.

So? If you then want to develop the code, do you put the new code in a
new file and then use a program to include it, or do you put unnamed
text in the already existing file?
 
A

Antoon Pardon

Op 2004-10-12 said:
| > gabriele renzi wrote:
| >> 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.
| >
| > But because of Python's line- and indentation-based syntax, doing all of
| > that on a single line is... um... awkward at best, to put it mildly.
|
| Which is one of the reasons I think the indentation-based syntax was
| a mistake. If the syntax becomes an argument against a construct
| in the language, something is wrong with the syntax IMO.

Indentation based structure is a godsend; a divine insight if you may.
Python is much much better for it.

That's your opinion I disagree.

I find it especially annoying when I work interactively. I sometimes
copy and paste something from an other window and it is just frustrating
to get a syntax error back just because you had copied an extra space
in front of the expression.
However, just beacuse it can use
indentation, doesn't mean that indentation should be mandated for every
case. Python uses {} and [] to scope dict and list items, but this does
not mean that a indentation based version of this wouldn't be welcome.
In general, indentation is great for "outer-structure" that is,
delimiting large code blocks. While delimiter based scoping is good
for inner structures, small blocks of code. It should not be an
either/or thing, one should properly have the option of using either
option depending upon which style brings the most clarity.

Well it isn't an either/or thing and I have seen it often enough that
a proposed language structure was argued against because fitting it
in the indentation-based syntax was going to be difficult/awkward or
something like that. Suppose for the sake af the argument that someone
comes up with a language structute that has almost everyone agree with
that it would be usefull to include in the language. However the
most natural indentation for the structure would be something like this:

start:

code

control:

code

control:

code

I fear that alone would kill the possibility of including it in
python.
 
M

Michael Hobbs

Dave Benjamin said:
Now, imagine you are setting up an animation this way:

after(10, lambda: sprite.move(0, 5))
after(15, lambda: sprite2.rotate(30))
after(20, lambda: sprite.scale(120, 120))
after(22, lambda: sprite2.move(50, 50))
after(22, lambda: sound1.play())
after(23, lambda: sprite.move(0, 0))
after(26, lambda: sound1.stop())

Others have already mentioned altering the definition of the after()
function, but you do not always have a pre-existing function that does
exactly what you want, such as sprite2.rotate() or sound1.play(). Here
is how I would do it, if lambda wasn't available:

def lambda_():
sprite.move(0, 5)
after(10, lambda_)
def lambda_():
sprite2.rotate(30)
after(15, lambda_)
def lambda_():
sprite.scale(120, 120)
after(20, lambda_)
etc...

I haven't verified this code in an actual interpreter, but I see no
reason why it shouldn't work. I don't believe that there is any restriction
on redefining functions. (pychecker might complain, though)

This style isn't PEP 8 compliant, but if you don't like having two extra
lines, you can always shrink it down to just one extra:

def lambda_(): sprite.move(0, 5)
after(10, lambda_)
def lambda_(): sprite2.rotate(30)
after (15, lambda_)
etc...


- Michael Hobbs
 
M

Michael Hobbs

Clark C. Evans said:
In general, indentation is great for "outer-structure" that is,
delimiting large code blocks. While delimiter based scoping is good
for inner structures, small blocks of code. It should not be an
either/or thing, one should properly have the option of using either
option depending upon which style brings the most clarity.

The Haskell language (http://www.haskell.org) does exactly this. It uses
indentation to infer structure, but the programmer is allowed to explicitly
state structure using semicolons and braces.

- Michael Hobbs
 
J

Jeff Shannon

Clark said:
In general, indentation is great for "outer-structure" that is,
delimiting large code blocks. While delimiter based scoping is good
for inner structures, small blocks of code. It should not be an
either/or thing, one should properly have the option of using either
option depending upon which style brings the most clarity.

Except that the Python philosophy is that overall, the greatest clarity
is achieved by having a single obvious way to do things. In this
viewpoint, there may be individual cases where delimiter-based scoping
is clearer, but these are only local maxima; the use of a mixture of
different styles (indentation and delimiters) will, over the entire
corpus of Python-language programming, result in significantly less
total clarity.

Jeff Shannon
Technician/Programmer
Credit International
 

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,774
Messages
2,569,599
Members
45,166
Latest member
DollyBff32
Top