Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Re: Securing a future for anonymous functions in Python

Reply
Thread Tools

Re: Securing a future for anonymous functions in Python

 
 
Jp Calderone
Guest
Posts: n/a
 
      12-30-2004
On Fri, 31 Dec 2004 00:19:29 +1000, Nick Coghlan <(E-Mail Removed)> wrote:
>Jp Calderone wrote:
> > On Fri, 31 Dec 2004 00:00:31 +1000, Nick Coghlan <(E-Mail Removed)> wrote:
> >
> >>Paul Rubin wrote:
> >>
> >>>Nick Coghlan <(E-Mail Removed)> writes:
> >>>
> >>>
> >>>>Anyway, I'm looking for feedback on a def-based syntax that came up in
> >>>>a recent c.l.p discussion:
> >>>
> >>>
> >>>Looks like just an even more contorted version of lambda. It doesn't
> >>>fix lambda's main deficiency which is inability to have several
> >>>statements in the anonymous function.
> >>
> >>Do you consider generator expressions or list comprehensions deficient because
> >>they don't allow several statements in the body of the for loop?
> >>

> >
> >
> > >>> (foo + bar

> > ... for foo in range(13) if foo % 3 == 2
> > ... for bar in range(16, 23) if 2 <= bar % 5 < 4)
> > <generator object at 0xb7dec10c>
> > >>>

> >
> > Hmm. Two for loops and two if clauses. That's four altogether.
> > Does that qualify as "several"? Sure, they're not statements
> > according to the grammar, but that's entirely beside the point.
> >
> > Jp

>
> And that's an expression, and hence perfectly legal as the body of an anonymous
> function.


Quoting my response again:

> Jp Calderone wrote:
> > Sure, they're not statements according to the grammar, but
> > that's entirely beside the point.


I thought this was obvious to anyone, oh well.

List and generator comprehensions have special syntax so that behavior
normally acheivable only with statements can be used to control their
execution. Lambdas don't have any similar special syntax.

I'm not saying "boo hoo lambdas are crippled fix them waah". I'm saying
"Lambdas and generator comprehensions are not comparable in this sense and
arguments based on one should not be used to support positions about the
other".

Jp
 
Reply With Quote
 
 
 
 
Paul L. Du Bois
Guest
Posts: n/a
 
      12-30-2004
Jp Calderone wrote:
> I'm not saying "boo hoo lambdas are crippled fix them waah". I'm

saying
> "Lambdas and generator comprehensions are not comparable in this

sense and
> arguments based on one should not be used to support positions about

the
> other".


This post and Michael Spencer's post which proposed (expr for args(a,
*b, **c)) got me wondering whether this could be done already today.
My solution is unfortuantely implementation-specific. I can't find a
way for a generator (let alone a generator expression) to refer to
itself; neither do generators have writable attributes. With those
features, one can imagine a more portable (and more verbose) solution.

I find that I don't really like the generator-like syntax. To me, it
makes sense for an unnamed function to look like a named function
without a name, eg:

callbacks['foo'] = def (a,b): ... expr or statement? ...

It seems to work in Lua (not that I'm a big fan of Lua). Thus, I'm not
sure what my point is with this code; maybe just that there are
workarounds if lambda ceases to exist. Also, with this sort of
solution, nobody can complain that genexps/listcomps/"lambdas" get
preferential treatment <wink>

Anyway, this is tested in Win32 python 2.4. It adds a function "fn"
(name stolen from Arc) which turns a specially-written generator
expression into an anonymous function. Default args, *args, *kwargs
are all unsupported. I'm sorry if google groups eats my leading
whitespace; I've one-lined things to reduce the effect.

def fn(gen):
"""Turns a generator expression into a callable."""
def anonymous(*args): return gen.next()
return anonymous

def args():
"""Works with fn(); yields args passed to anonymous()."""
while True: yield sys._getframe(2).f_locals['args']

args = args()

foo = fn(a + b * c for (a,b,c) in args)
assert foo(3,4,5) == 3+4*5
assert foo(4,5,6) == 4+5*6

 
Reply With Quote
 
 
 
 
Alex Martelli
Guest
Posts: n/a
 
      12-31-2004
Paul L. Du Bois <(E-Mail Removed)> wrote:
...
> are all unsupported. I'm sorry if google groups eats my leading
> whitespace; I've one-lined things to reduce the effect.


It does/did, so let me repost while fixing it since this is truly,
deliciously evil:

> def fn(gen):
> """Turns a generator expression into a callable."""
> def anonymous(*args): return gen.next()
> return anonymous
>
> def args():
> """Works with fn(); yields args passed to anonymous()."""
> while True: yield sys._getframe(2).f_locals['args']
>
> args = args()
>
> foo = fn(a + b * c for (a,b,c) in args)
> assert foo(3,4,5) == 3+4*5
> assert foo(4,5,6) == 4+5*6


Paul, you really SHOULD have posted this BEFORE I had to send in the
files for the 2nd ed's Coobook... this gets my vote for the most
delightful abuse of sys._getframe even (and I've seen quite a few.

Kudos!!!


Alex
 
Reply With Quote
 
Steven Bethard
Guest
Posts: n/a
 
      12-31-2004
Alex Martelli wrote:
> Paul L. Du Bois <(E-Mail Removed)> wrote:
>>def fn(gen):
>> """Turns a generator expression into a callable."""
>> def anonymous(*args): return gen.next()
>> return anonymous
>>
>>def args():
>> """Works with fn(); yields args passed to anonymous()."""
>> while True: yield sys._getframe(2).f_locals['args']
>>
>>args = args()
>>
>>foo = fn(a + b * c for (a,b,c) in args)
>>assert foo(3,4,5) == 3+4*5
>>assert foo(4,5,6) == 4+5*6

>
>
> Paul, you really SHOULD have posted this BEFORE I had to send in the
> files for the 2nd ed's Coobook... this gets my vote for the most
> delightful abuse of sys._getframe even (and I've seen quite a few.


So, I couldn't figure out why this worked until I started to write an
email to ask. Once I understood it, I figured it wouldn't hurt to send
my thoughts out anyway to (1) verify that I understand it right, and (2)
help anyone else who was trying to figure this out.


As I understand it sys._getframe(2).f_locals should get the names local
to the stack frame two above the current one. So, in the context of:
fn(... for ... in args)
sys._getframe(2).f_locals should be looking at the names local to the
'anonymous' function in the 'fn' function, because one stack frame up
from the 'args' function is the generator's 'next' function, and two
stack frames up is the 'anonymous' function. That means that:
sys._getframe(2).f_locals['args']
gets whatever object has been bound to 'args' in:
def anonymous(*args):
So then in:
foo = fn(a + b * c for (a,b,c) in args)
foo(3,4,5)
foo(4,5,6)
sys._getframe(2).f_locals['args'] will get (3, 4, 5) in the first foo
call, (4, 5, 6) in the second foo call, etc.


So basically the way a call like foo(3, 4, 5) works is:
(1) foo(3, 4, 5) calls gen.next() where gen is the generator expression
(2) gen.next() calls args.next()
(3) args.next() returns the (3, 4, 5) argument tuple of foo by looking
up the stack frames
(4) gen.next() binds (3, 4, 5) to the names a, b, c respectively
(5) gen.next() returns the value of "a + b * c" for these bindings
(6) foo(3, 4, 5) returns the same value (as gen.next() did)

Does that seem about right?

Steve

P.S. That's so *evilly* cool!
 
Reply With Quote
 
Alex Martelli
Guest
Posts: n/a
 
      12-31-2004
Steven Bethard <(E-Mail Removed)> wrote:

> Does that seem about right?


Yep!

> P.S. That's so *evilly* cool!


We should have an Evilly Cool Hack of the Year, and I nominate Paul du
Bois's one as the winner for 2004. Do I hear any second...?


Alex
 
Reply With Quote
 
Paul Rubin
Guest
Posts: n/a
 
      12-31-2004
http://www.velocityreviews.com/forums/(E-Mail Removed) (Alex Martelli) writes:
> We should have an Evilly Cool Hack of the Year, and I nominate Paul du
> Bois's one as the winner for 2004. Do I hear any second...?


The year's not over yet .
 
Reply With Quote
 
Paul Du Bois
Guest
Posts: n/a
 
      12-31-2004
Alex Martelli wrote:
> We should have an Evilly Cool Hack of the Year, and I nominate Paul

du
> Bois's one as the winner for 2004. Do I hear any second...?


Thank you

I am busy writing it up as a recipe. I think I have a pleasing way for
it to be portable, even. Unfortunately, that removes some of the evil.
p

 
Reply With Quote
 
Paul L. Du Bois
Guest
Posts: n/a
 
      12-31-2004
Alex Martelli wrote:
> We should have an Evilly Cool Hack of the Year, and I nominate
> Paul Du Bois's one as the winner for 2004. Do I hear any second...?


Oh bother, I just realized I sent my first reply using a good email
address. Hope that cancel goes through quickly.

Anyway, thank you! I've submitted it as a recipe. It includes a
less-evil portable version, which might be improved further if PEP 288
ever comes through.

p

The recipe:
http://aspn.activestate.com/ASPN/Coo.../Recipe/361452

 
Reply With Quote
 
Steven Bethard
Guest
Posts: n/a
 
      01-01-2005
Paul Rubin wrote:
> (E-Mail Removed) (Alex Martelli) writes:
>
>>We should have an Evilly Cool Hack of the Year, and I nominate Paul du
>>Bois's one as the winner for 2004. Do I hear any second...?

>
> The year's not over yet .


Ok, now that we're past 0:00:00 UTC, I'll second that nomination!

Steve

P.S. Happy New Year all!
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Would Anonymous Functions Help in Learning Programming/Python? Cristian Python 66 09-24-2007 03:26 PM
Is this a local anonymous class or a member anonymous class Reporter Java 3 05-12-2007 05:23 AM
help with an anonymous array of anonymous hashes noeldamonmiller@gmail.com Perl Misc 1 02-10-2005 01:08 AM
Securing a future for anonymous functions in Python Nick Coghlan Python 85 01-12-2005 11:24 PM
please help me in distinguish redefining functions, overloading functions and overriding functions. Xiangliang Meng C++ 1 06-21-2004 03:11 AM



Advertisments