By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,240 Members | 791 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,240 IT Pros & Developers. It's quick & easy.

Anonymus functions revisited

P: n/a
Since George Sakkis proposed a new way of doing list comprehensions

http://groups-beta.google.com/group/...ff1b81fa70c8a7

letting tuples-like objects (x,y,z=0) acting as functions on other
tuples I wonder why this would not be a good starting point of
rethinking anonymus functions?

In Georges proposition the action is

(x,y,z=0) -> (x,y,z)

i.e. mapping tuples on other tuples. This is equivalent to

lambda x,y,z=0:(x,y,z)

But regarding tuples as actions by means of an arrow "->" would
generalize this idea:

Mappings like that:

((x,y),z) -> x+y-z

((x,y=0),z) -> None

should be valid actions too.

What is the audience thinking about that?

Regards Kay

Jul 18 '05 #1
Share this Question
Share on Google+
37 Replies


P: n/a
Kay Schluehr wrote:
Since George Sakkis proposed a new way of doing list comprehensions

http://groups-beta.google.com/group/...ff1b81fa70c8a7

letting tuples-like objects (x,y,z=0) acting as functions on other
tuples I wonder why this would not be a good starting point of
rethinking anonymus functions?

In Georges proposition the action is

(x,y,z=0) -> (x,y,z)

i.e. mapping tuples on other tuples. This is equivalent to

lambda x,y,z=0:(x,y,z)

But regarding tuples as actions by means of an arrow "->" would
generalize this idea:

Mappings like that:

((x,y),z) -> x+y-z

((x,y=0),z) -> None

should be valid actions too.

What is the audience thinking about that?


IMHO, it's just lambda in disguise, and I'm not sure it's more readable
than lambda. You'll have to provide more arguments (sorry for the pun
!-) to gain my adhesion. (NB : I could use this syntax without problem,
it's just that we already have a syntax for this).
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Jul 18 '05 #2

P: n/a
Ron
On 21 Mar 2005 22:37:42 -0800, "Kay Schluehr" <ka**********@gmx.net>
wrote:
Mappings like that:

((x,y),z) -> x+y-z

((x,y=0),z) -> None

should be valid actions too.

What is the audience thinking about that?


I think that there's too much implied, and that in the long run it,
if we keep addding in special shortcuts, it will lead to very dificult
to read code.
Jul 18 '05 #3

P: n/a
> letting tuples-like objects (x,y,z=0) acting as functions on other
tuples I wonder why this would not be a good starting point of
rethinking anonymus functions?

In Georges proposition the action is

(x,y,z=0) -> (x,y,z)

i.e. mapping tuples on other tuples. This is equivalent to

lambda x,y,z=0:(x,y,z)


As you say for yourself, that's just lambda in disguise. So I guess the same
arguments about the in- or exclusion of lambda apply here. I personally
like lambda, but _can_ live without it.

--
Regards,

Diez B. Roggisch
Jul 18 '05 #4

P: n/a
bruno modulix wrote:
Kay Schluehr wrote:
Since George Sakkis proposed a new way of doing list comprehensions

http://groups-beta.google.com/group/...ff1b81fa70c8a7
letting tuples-like objects (x,y,z=0) acting as functions on other
tuples I wonder why this would not be a good starting point of
rethinking anonymus functions?

In Georges proposition the action is

(x,y,z=0) -> (x,y,z)

i.e. mapping tuples on other tuples. This is equivalent to

lambda x,y,z=0:(x,y,z)
which is in fact not a valid solution in the context of Georges'
problem... (or I failed to get it to work !-)

But regarding tuples as actions by means of an arrow "->" would
generalize this idea:

Mappings like that:

((x,y),z) -> x+y-z

((x,y=0),z) -> None

should be valid actions too.

What is the audience thinking about that?

IMHO, it's just lambda in disguise, and I'm not sure it's more readable
than lambda. You'll have to provide more arguments (sorry for the pun
!-) to gain my adhesion. (NB : I could use this syntax without problem,
it's just that we already have a syntax for this).


Changing my mind after a more torough re-reading of the original thread
and few tests... The original problem is about tuple unpacking. The
proposed solution solves this problem, *and* can (could ?) be a
replacement for lambdas.

hmmm... I like the idea of having a more flexible tuple unpacking with a
function-call-like semantic, but I'm still not sure to like the idea of
replacing lambda with the proposed syntax.

needs-some-more-thinking-on-this-ly'yrs

--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Jul 18 '05 #5

P: n/a
Diez B. Roggisch wrote:
letting tuples-like objects (x,y,z=0) acting as functions on other
tuples I wonder why this would not be a good starting point of
rethinking anonymus functions?

In Georges proposition the action is

(x,y,z=0) -> (x,y,z)

i.e. mapping tuples on other tuples. This is equivalent to

lambda x,y,z=0:(x,y,z)

As you say for yourself, that's just lambda in disguise.


Not exactly in fact - unless I messed something. There are 2 problems
here: a more flexible tuple unpacking, *and* a lambda in disguise.
Actually, I'd go + 1 for the first, -1 for the second
So I guess the same
arguments about the in- or exclusion of lambda apply here.
For the second part, yes. Not for the first one.
I personally
like lambda, but _can_ live without it.


Yes, one can live without...
<troll>
....and without list comprehensions, __call__ and other special methods,
descriptors, metaclasses, first class functions, builtin datatypes like
lists and dicts, exceptions, dynamic typing, garbage collection, etc
too. Hurray, let's all happily program in assembly !-)
</troll>

--
bruno desthuilliers
ruby -e "print 'o****@xiludom.gro'.split('@').collect{|p|
p.split('.').collect{|w| w.reverse}.join('.')}.join('@')"
Jul 18 '05 #6

P: n/a
> Not exactly in fact - unless I messed something. There are 2 problems
here: a more flexible tuple unpacking, *and* a lambda in disguise.
Actually, I'd go + 1 for the first, -1 for the second
The proposed syntax from Kay is lambda in disguise. To make it work like
George want it is modifying the unpacking behaviour. Actually while Kay
proposed his syntax as result of the discussion started by George it won't
work for that case. The reason is simply that the lambda form returns a
tuple, but does not make any revelations about the variable names that
tuple shall be unpacked to.

So they are in fact unrelated - at least if introduced as declared. An
augmentation to fulfill George's wishes could look like this:

[a,b,c for a,b,c: (x,y,z=0)-> x,y,z) in values]
Yes, one can live without...
<troll>
...and without list comprehensions, __call__ and other special methods,
descriptors, metaclasses, first class functions, builtin datatypes like
lists and dicts, exceptions, dynamic typing, garbage collection, etc
too. Hurray, let's all happily program in assembly !-)
</troll>


You are right, but for lambda in its current limited form short, named
functions are a good replacement. I don't want to get rid of lambda - but
since listcomps got introduced, 95% of my usages of them disappeared.

--
Regards,

Diez B. Roggisch
Jul 18 '05 #7

P: n/a
Ron
On Tue, 22 Mar 2005 15:05:55 +0100, bruno modulix <on***@xiludom.gro>
wrote:
bruno modulix wrote:
Kay Schluehr wrote:
Since George Sakkis proposed a new way of doing list comprehensions letting tuples-like objects (x,y,z=0) acting as functions on other
tuples I wonder why this would not be a good starting point of
rethinking anonymus functions?

In Georges proposition the action is

(x,y,z=0) -> (x,y,z)


What about a safe exec as a replacement to lamba but witht he
flexability of exec in a safe and limeted way?

safe_exec ( (*inputs) , (expressionstring) , ( *outputs) )

Functon to return a default value: def dfv( arg = value): return arg

Safe exec command: x, y = 1, 2
safeexec ( (x, y, dfv(z=0)), "# do nothing", ( x, y, z) ) (1, 2, 0)

What could we do, not do with this?

* I actually started this reply here, so below is how I got to the
above exression.
I'm trying to put my finger on the basic inconsistency here. It has
something to do with the z=0 as a way to defining a default .

Then there's the lamba which I hear may be removed, but is difficult
to understand for beginners, and isn't readable in that the name
doesn't say what it does. An alternative name, and possibly a
simpler syntax would be a plus.

Another concept that this touches is the indirect execution of an
expression. Exec and eval do that, but then you introduce security
issues.

I'm wondering if there's a fundamental concept under these issues such
as a base function class or command that can evaluate the contents of
a tuple in a secure way?

value = fn(arg, returnvalue)
x = 1
fn( x, x*2) 2

Use lists or tuples for multiple arguments and return expressions:
x, y, z = 1, 2, 3
fn( (x,y,z=0), (x,y,z) ) (1, 2, 3)

But it's that "z=0" causes problems here. In a tuple it's equivalent
to saying 1=2. or 'a'='b'

So we need a way to say 'if name is undefined, bind it to object'.

# function to give a default value
def dfv( arg = value):
return arg
x, y = 1, 2
fn( (x, y, dfv(x=0)), ( x, y, z )) (1, 2, 3)

Now since this could execute in it's own private space, it might also
offer a way to use exec or eval() indirectly in a very limited and
safe way.
estring = \ """
result = ''
data = 'abcdefghigklmnop'
for ch in data:
if ch != filterc:
result.join(ch)
""" fn( ( dfv(filterc='d'), evalstring), (exec estring) )
So we need to use a three item tuple:

safe_exec ( (*inputs) , (expressionstring) , ( *outputs) )
def dfv( arg = value): return arg x, y = 1, 2
safeexec( (x, y, dfv(z=0)), "# do nothing", ( x, y, z) )

(1, 2, 0)

Long way around to here, but is this something that has potential?
It would have to be a built in to ensure it's safe to use. But with
an exec string, it can possibly do a lot more than lamba, and it
probably wouldn't be as fast. But the flexibility could be useful.

Ron



Jul 18 '05 #8

P: n/a
Ron a écrit :
(snip)
def dfv( arg = value):
return arg
def dfv( arg = value):

.... return arg
....
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'value' is not defined

And sorry, but -1 for using exec here.
Jul 18 '05 #9

P: n/a
Ron a écrit :
On 21 Mar 2005 22:37:42 -0800, "Kay Schluehr" <ka**********@gmx.net>
wrote:

Mappings like that:

((x,y),z) -> x+y-z

((x,y=0),z) -> None

should be valid actions too.

What is the audience thinking about that?

I think that there's too much implied, and that in the long run it,
if we keep addding in special shortcuts, it will lead to very dificult
to read code.

Don't like Perl ?-)

The problem here is that Kay's proposition mixes two points: flexible
tuple unpacking and a new syntax for anonymous functions.

Jul 18 '05 #10

P: n/a
Diez B. Roggisch a écrit :
(snip)
You are right, but for lambda in its current limited form short, named
functions are a good replacement.


-inf on this !-)

Jul 18 '05 #11

P: n/a
Ron
On Tue, 22 Mar 2005 21:43:48 +0100, Bruno Desthuilliers
<bd*****************@free.quelquepart.fr> wrote:
Ron a écrit :
(snip)
def dfv( arg = value):


return arg
def dfv( arg = value):... return arg
...
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'value' is not defined

And sorry, but -1 for using exec here.

Yes, I cought that myself. So...

try: z=z
except: z=0

or

if 'z' not in locals():
z = 0

Ok, thinking in more incremental terms...

Why should a function not create a local varable of an argument if the
varable doesn't exist and a default value is given?

So when:

Def dfv( v=0):
return v
dfv() 0 ;it creates the local copy in this case.
a = 25
dfv(a) 25 ;It used the given value as expected.
dfv(b)

Traceback (most recent call last):
File "<pyshell#4>", line 1, in -toplevel-
dfv(b)
NameError: name 'b' is not defined

Why not let it set the local varable v to the default as it does when
no varable is specified?

A function without a default would still give an error as expected.
:)
Ok no exec, but what about the general syntax?

value = keyword (inputargs, command, outputargs)

I was thinking if it can be done with standard tuples, it has the
potential to be passed around easily and work from lists and
dictionaries.

Ron

Jul 18 '05 #12

P: n/a
Ron
On Tue, 22 Mar 2005 21:56:57 GMT, Ron <ra****@tampabay.rr.com> wrote:
Why should a function not create a local varable of an argument if the
varable doesn't exist and a default value is given?


ok... thought it out better. :)

Getting a default into a function isn't the problem. Returning the
value to a varable that doesn't exist is.

So then the question is ... is there a way for a function to create a
varable in it's parents namespace that persists after the function is
done?

Jul 18 '05 #13

P: n/a
"Ron" <ra****@tampabay.rr.com> wrote:
On Tue, 22 Mar 2005 21:56:57 GMT, Ron <ra****@tampabay.rr.com> wrote:
Why should a function not create a local varable of an argument if the
varable doesn't exist and a default value is given?


ok... thought it out better. :)

Getting a default into a function isn't the problem. Returning the
value to a varable that doesn't exist is.

So then the question is ... is there a way for a function to create a
varable in it's parents namespace that persists after the function is
done?


Yeap.. a simple one-liner can do the trick:

def makeVars(**nameVals):
sys._getframe(1).f_locals.update(nameVals)

try: b
except NameError: print "Before makeVars: NameError"
else: print "Before makeVars: Not NameError"
makeVars(b=2)
try: b
except NameError: print "After makeVars: NameError"
else: print "After makeVars: Not NameError"

George
Jul 18 '05 #14

P: n/a
Ron
On Tue, 22 Mar 2005 18:15:25 -0500, "George Sakkis"
<gs*****@rutgers.edu> wrote:
"Ron" <ra****@tampabay.rr.com> wrote:
On Tue, 22 Mar 2005 21:56:57 GMT, Ron <ra****@tampabay.rr.com> wrote:
>Why should a function not create a local varable of an argument if the
>varable doesn't exist and a default value is given?


Yeap.. a simple one-liner can do the trick:

def makeVars(**nameVals):
sys._getframe(1).f_locals.update(nameVals)

try: b
except NameError: print "Before makeVars: NameError"
else: print "Before makeVars: Not NameError"
makeVars(b=2)
try: b
except NameError: print "After makeVars: NameError"
else: print "After makeVars: Not NameError"

George


Cool! Thanks George, so I can do this:

# Set a varable to a default value if it doesn't exist.
# Return the same value back if it does.
# Use: varable = dfvalue( varable=object)
def defvalue(**var):
if var.keys()[0] not in sys._getframe(1).f_locals.keys():
return var.values()[0]
return sys._getframe(1).f_locals[var.keys()[0]]

f = defvalue(f=0)
print f # 0

g = 19
g = defvalue(g=0)
print g # 19
Would there be any problems with using this function?

Not sure where I need it. Was thinking it could be used inside
expressions somehow, and it was an iteresting problem. ;)

Ron
Jul 18 '05 #15

P: n/a
Ron
On Tue, 22 Mar 2005 21:45:42 +0100, Bruno Desthuilliers
<bd*****************@free.quelquepart.fr> wrote:
Ron a écrit :
On 21 Mar 2005 22:37:42 -0800, "Kay Schluehr" <ka**********@gmx.net>
wrote:

Mappings like that:

((x,y),z) -> x+y-z

((x,y=0),z) -> None

should be valid actions too.

What is the audience thinking about that?

I think that there's too much implied, and that in the long run it,
if we keep addding in special shortcuts, it will lead to very dificult
to read code.

Don't like Perl ?-)


I tried it.. Wrote a html reformatter in it a long time ago. Wasn't
tempted to do anything else with it. It was good for that, but I went
a month later and had trouble figuring out how it worked. :)
The problem here is that Kay's proposition mixes two points: flexible
tuple unpacking and a new syntax for anonymous functions.


Yes, two different problems. I don't think anything needs to be done
to tuples myself. I tend to use lists more anyway.
As far as anonymous functions go... What if there where a container
type to hold unexecuted python code until it is asked to do it. And to
be able to assign it a name, so it would have an object class and
type. But be defined by like a tuple. No addition syntax to make
things confusing.
sum = (* a = b+c *)
The (* and *) could be something more appropriate. As long as it's
easy to identify and can't be confused with anything else.
There would be an order of precedence to it also so you could do:
my_button_action = (*a+=c (*if b:c=1 (*if not z: b=False*) *) *)
It would execute from the inside (*_*) outward and use the local name
space it's executed in, so no passing arguments or return values.

Nesting and order of precedence has worked for a long time. to
evaluate it you would need a keyword...
newlamba my_button_action

or this could be valid:newlamba (* a+=c (* if b:c=1 (* if not z:b=False *) *) *)
or left to right order of execution:newlamba (* a = b+c+d, if a>limit:done=True *)
If argument passing is really needed, I suppose there could be an
export/inport method attached to it.
newlamba (* sum = a+b *).import(a,b).export(sum)
ornewlamba (* sum = a+b *).in_out(a,b -> sum) newlamba my_button_action.in_out(a,b ->sum)

A differnt name would be nice... code, docode, dothis, process... ?

or if you require the in_out method to start it, you don't need the
keyword.

mybutton = (* sum = a+b *) # does not execute, but binds it to a b = mybutton.in_out(a,b -> sum) # This evaluates first, the sum is bound to b. b = (* sum = a+b *).in_out(a,b -> sum) # Is the same as above.

Yes, there are probably loads of stuff wrong with this. ;-)

Ron Adam

(Looks like another Ron joined the group.)
Jul 18 '05 #16

P: n/a
Op 2005-03-22, Diez B. Roggisch schreef <de*********@web.de>:
Not exactly in fact - unless I messed something. There are 2 problems
here: a more flexible tuple unpacking, *and* a lambda in disguise.
Actually, I'd go + 1 for the first, -1 for the second


The proposed syntax from Kay is lambda in disguise. To make it work like
George want it is modifying the unpacking behaviour. Actually while Kay
proposed his syntax as result of the discussion started by George it won't
work for that case. The reason is simply that the lambda form returns a
tuple, but does not make any revelations about the variable names that
tuple shall be unpacked to.

So they are in fact unrelated - at least if introduced as declared. An
augmentation to fulfill George's wishes could look like this:

[a,b,c for a,b,c: (x,y,z=0)-> x,y,z) in values]
Yes, one can live without...
<troll>
...and without list comprehensions, __call__ and other special methods,
descriptors, metaclasses, first class functions, builtin datatypes like
lists and dicts, exceptions, dynamic typing, garbage collection, etc
too. Hurray, let's all happily program in assembly !-)
</troll>


You are right, but for lambda in its current limited form short, named
functions are a good replacement. I don't want to get rid of lambda - but
since listcomps got introduced, 95% of my usages of them disappeared.


I don't understand why people always say short named functions are a
good replacement. IMO list comprehensions and generator expressions
use lambda's in disguise. When we write something like
[x * x for x in some_iterator], nobody seems to have problems that
we just write an expression here and nobody is argueing that we
should define a short function. However when people need the
same kind of semantics in their function, being an expression that
is being reevaluated with different values, for which lambda is the
natural candidate, suddenly we should use short named functions.

Can someone who thinks this way, please explain why this is acceptable

[ x * x for x in some_iterator ]

But this is not

map(lambda x: x * x, some_iteraror)

and should be replaced with

def sqr(x): return x * x
map(sqr , some_iterator)

--
Antoon Pardon
Jul 18 '05 #17

P: n/a
Ron wrote:
On Tue, 22 Mar 2005 21:56:57 GMT, Ron <ra****@tampabay.rr.com> wrote:

Why should a function not create a local varable of an argument if the
varable doesn't exist and a default value is given?

ok... thought it out better. :)

Getting a default into a function isn't the problem. Returning the
value to a varable that doesn't exist is.

So then the question is ... is there a way for a function to create a
varable in it's parents namespace that persists after the function is
done?


yes, that'w called a global, and it's UGLY(tm)
def yuck(): .... global G
.... G = 42
.... G Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'G' is not defined yuck()
G 42


Anyone doing such a thing in my team would be shoot down at once !-)

--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Jul 18 '05 #18

P: n/a
George Sakkis wrote:
"Ron" <ra****@tampabay.rr.com> wrote:
On Tue, 22 Mar 2005 21:56:57 GMT, Ron <ra****@tampabay.rr.com> wrote:

Why should a function not create a local varable of an argument if the
varable doesn't exist and a default value is given?


ok... thought it out better. :)

Getting a default into a function isn't the problem. Returning the
value to a varable that doesn't exist is.

So then the question is ... is there a way for a function to create a
varable in it's parents namespace that persists after the function is
done?

Yeap.. a simple one-liner can do the trick:

def makeVars(**nameVals):
sys._getframe(1).f_locals.update(nameVals)

try: b
except NameError: print "Before makeVars: NameError"
else: print "Before makeVars: Not NameError"
makeVars(b=2)
try: b
except NameError: print "After makeVars: NameError"
else: print "After makeVars: Not NameError"


Interesting. I'll keep a copy of this one in my cookbook for further
exploration. But I think I would use such a thing in production code.
b = 25
makeVars(b=88)
b

88
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Jul 18 '05 #19

P: n/a
Ron wrote:
On Tue, 22 Mar 2005 21:45:42 +0100, Bruno Desthuilliers
<bd*****************@free.quelquepart.fr> wrote:

Ron a écrit :
On 21 Mar 2005 22:37:42 -0800, "Kay Schluehr" <ka**********@gmx.net>
wrote:

Mappings like that:

((x,y),z) -> x+y-z

((x,y=0),z) -> None

should be valid actions too.

What is the audience thinking about that?
I think that there's too much implied, and that in the long run it,
if we keep addding in special shortcuts, it will lead to very dificult
to read code.

Don't like Perl ?-)

I tried it.. Wrote a html reformatter in it a long time ago. Wasn't
tempted to do anything else with it. It was good for that, but I went
a month later and had trouble figuring out how it worked. :)


This was kind of rethorical question !-)
The problem here is that Kay's proposition mixes two points: flexible
tuple unpacking and a new syntax for anonymous functions.

Yes, two different problems. I don't think anything needs to be done
to tuples myself. I tend to use lists more anyway.


They are two different beasts. Note that you don't have anything like
list unpacking, now tuple unpacking is pretty common in Python (swap,
multiple return values, formatted strings and outputs, ...).

As far as anonymous functions go... (snip prospective code)

Yes, there are probably loads of stuff wrong with this. ;-)


Err... Isn't it a bit more complicated than our actual lambdas ?-)

--
bruno desthuilliers
ruby -e "print 'o****@xiludom.gro'.split('@').collect{|p|
p.split('.').collect{|w| w.reverse}.join('.')}.join('@')"
Jul 18 '05 #20

P: n/a
George Sakkis wrote:
So then the question is ... is there a way for a function to create a
varable in it's parents namespace that persists after the function is
done?


Yeap.. a simple one-liner can do the trick:

def makeVars(**nameVals):
sys._getframe(1).f_locals.update(nameVals)

try: b
except NameError: print "Before makeVars: NameError"
else: print "Before makeVars: Not NameError"
makeVars(b=2)
try: b
except NameError: print "After makeVars: NameError"
else: print "After makeVars: Not NameError"


Do I really need to mention that the whole concept here is broken. This
only works if you call it from global scope. If you call it from inside a
function it [usually] won't work:
def makeVars(**nameVals): sys._getframe(1).f_locals.update(nameVals)

def test(): try: b
except NameError: print "Before makeVars: NameError"
else: print "Before makeVars: Not NameError"
makeVars(b=2)
try: b
except NameError: print "After makeVars: NameError"
else: print "After makeVars: Not NameError"

import sys
test() Before makeVars: NameError
After makeVars: NameError

Jul 18 '05 #21

P: n/a
> Can someone who thinks this way, please explain why this is acceptable

[ x * x for x in some_iterator ]

But this is not

map(lambda x: x * x, some_iteraror)

and should be replaced with

def sqr(x): return x * x
map(sqr , some_iterator)


It shouldn't, it should be replaced with the listcomp. And IMHO it results
in better readable code.

AFAIK the reason people say you should use named functions is _not_ because
of these single expression replacements. The reason is that frequently
people complain about lambda being so restrictive so that you can't write

lambda x,y: if x > 100: x else: y

and want to _extend_ lambda beyond its current capabilities and make it full
featured but anonymous functions.

And these requests are rebuked with the argument that having to give a more
complex function a name instead of declaring it anonymously doesn't cost
you much - especially since you can declare them inside other functions so
the global namespace isn't cluttered.

I have to admit that rereading my statement

"""
You are right, but for lambda in its current limited form short, named
functions are a good replacement
"""

is not really what I wanted to say.

I should have written:

"""
for lambda in its current limited form, listcomprehensions often are a good
replacement.
"""

But as I've said various times before: I personally don't mind lambdas and
for example the reduce function has been useful for me quite a few times,
can't be replaced by listcomps, and frequently needs a callable consisting
of only a single expression. So I'll continue to use lambdas there.

--
Regards,

Diez B. Roggisch
Jul 18 '05 #22

P: n/a
Duncan Booth wrote:
Do I really need to mention that the whole concept here is broken. This only works if you call it from global scope. If you call it from inside a function it [usually] won't work:
def makeVars(**nameVals): sys._getframe(1).f_locals.update(nameVals)

def test(): try: b
except NameError: print "Before makeVars: NameError"
else: print "Before makeVars: Not NameError"
makeVars(b=2)
try: b
except NameError: print "After makeVars: NameError"
else: print "After makeVars: Not NameError"

import sys
test() Before makeVars: NameError
After makeVars: NameError
Yes.

To put it short:

def makeVars(**nameVals):
print "prev",sys._getframe(1).f_locals["z"]
sys._getframe(1).f_locals.update(nameVals)
print "post",sys._getframe(1).f_locals["z"]

def test():
z = 0
makeVars(z=2)
z = 0
makeVars(z=3) prev 0
post 3
test()

prev 0
post 0
The Python runtime uses the opcodes STORE_FAST and LOAD_FAST to
store/access local variables of a function.

Take a closer look at the code:

case STORE_FAST:
v = POP();
SETLOCAL(oparg, v);
goto fast_next_opcode;

with

register PyObject **fastlocals

and macros

#define GETLOCAL(i) (fastlocals[i])
#define SETLOCAL(i, value) do { PyObject *tmp = GETLOCAL(i); \
GETLOCAL(i) = value; \
Py_XDECREF(tmp); } while (0)

The local variables will be stored in the pointer array fastlocals not
within a Python dict.

If a variable is created as a global it will be stored using the
STORE_NAME opcode instead:
case STORE_NAME:
w = GETITEM(names, oparg);
v = POP();
if ((x = f->f_locals) != NULL) {
if (PyDict_CheckExact(x))
err = PyDict_SetItem(x, w, v);
else
err = PyObject_SetItem(x, w, v);
Py_DECREF(v);
if (err == 0) continue;
break;
}
which clearly accesses a Python dict for storage.
Regards Kay

Jul 18 '05 #23

P: n/a
Op 2005-03-23, Diez B. Roggisch schreef <de*********@web.de>:
Can someone who thinks this way, please explain why this is acceptable

[ x * x for x in some_iterator ]

But this is not

map(lambda x: x * x, some_iteraror)

and should be replaced with

def sqr(x): return x * x
map(sqr , some_iterator)
It shouldn't, it should be replaced with the listcomp. And IMHO it results
in better readable code.


This misses the point. The fact that map and the listcomprehension do
the same stuff is just a detail. It is about giving a function an
expression as argument that is to be evaluated multiple times.
AFAIK the reason people say you should use named functions is _not_ because
of these single expression replacements. The reason is that frequently
people complain about lambda being so restrictive so that you can't write

lambda x,y: if x > 100: x else: y

and want to _extend_ lambda beyond its current capabilities and make it full
featured but anonymous functions.
This is one kind of people. An other kind of people seems to want to
get rid of lamda's altogether and asks whether it is so difficult
to make a named function each time you would otherwise use a lambda.
But as I've said various times before: I personally don't mind lambdas and
for example the reduce function has been useful for me quite a few times,
can't be replaced by listcomps, and frequently needs a callable consisting
of only a single expression. So I'll continue to use lambdas there.


Then my question was not meant for you.

--
Antoon Pardon
Jul 18 '05 #24

P: n/a
Ron
On 23 Mar 2005 10:13:16 GMT, Duncan Booth
<du**********@invalid.invalid> wrote:
Do I really need to mention that the whole concept here is broken. This
only works if you call it from global scope. If you call it from inside a
function it [usually] won't work:

That's only becuase it was asked to go up 1 frame, and not 2.
def makeVars(**nameVals):
sys._getframe(2).f_locals.update(nameVals) # <- get 2 frames up.
def test():
try: b
except NameError: print "Before makeVars: NameError"
else: print "Before makeVars: Not NameError"
makeVars(b=2)
try: b
except NameError: print "After makeVars: NameError"
else: print "After makeVars: Not NameError"
import sys
test()
Before makeVars: NameError
After makeVars: Not NameError


Jul 18 '05 #25

P: n/a
Ron
On 23 Mar 2005 10:13:16 GMT, Duncan Booth
<du**********@invalid.invalid> wrote:
Do I really need to mention that the whole concept here is broken. This
only works if you call it from global scope. If you call it from inside a
function it [usually] won't work:


Ok... you can get globals this way if you know how many frames up it
is. Not terrable useful. :/
def frame0():
print 'frame0 (locals): ',sys._getframe(0).f_locals
print '\nframe1 (parent): ',sys._getframe(1).f_locals
print '\n(Global) : ',sys._getframe(2).f_locals

def frame1():
frame0()

import sys
frame1()

frame0 (locals): {}

frame1 (parent): {}

(Global) : {'__builtins__': <module '__builtin__' (built-in)>, 'sys':
<module 'sys' (built-in)>, '__name__': '__main__', 'frame1': <function
frame1 at 0x00B437B0>, 'frame0': <function frame0 at 0x00B43770>,
'__doc__': None}


Jul 18 '05 #26

P: n/a
Ron wrote:
On 23 Mar 2005 10:13:16 GMT, Duncan Booth
<du**********@invalid.invalid> wrote:

Do I really need to mention that the whole concept here is broken. This only works if you call it from global scope. If you call it from inside a function it [usually] won't work:

That's only becuase it was asked to go up 1 frame, and not 2.

def makeVars(**nameVals):
sys._getframe(2).f_locals.update(nameVals) # <- get 2 frames up.

def test():
try: b
except NameError: print "Before makeVars: NameError"
else: print "Before makeVars: Not NameError"
makeVars(b=2)
try: b
except NameError: print "After makeVars: NameError"
else: print "After makeVars: Not NameError"
import sys
test()
Before makeVars: NameError
After makeVars: Not NameError


That's true only because the globals are updated by {"b":2}
two levels down.

If You nest the test() function You reproduce the error again:

def test():
def inner(): try: b
except NameError: print "Before makeVars: NameError"
else: print "Before makeVars: Not NameError"
makeVars(b=2)
try: b
except NameError: print "After makeVars: NameError"
else: print "After makeVars: Not NameError"
inner()
Before makeVars: NameError
After makeVars: NameError
A working makeVars seems not to be different from

def makeVars(**nameVals):
globals().update(nameVals)
Regards Kay

Jul 18 '05 #27

P: n/a
Kay Schluehr wrote:
A working makeVars seems not to be different from

def makeVars(**nameVals):
globals().update(nameVals)


Not quite. If Ron can come up with a working makeVars it would update the
caller's globals whereas what you just posted updates makeVar's globals so
there is a difference (when the makeVars and the calling function are in
different modules), just not a very useful one.
Jul 18 '05 #28

P: n/a
On 23 Mar 2005 08:31:36 GMT
Antoon Pardon <ap*****@forel.vub.ac.be> wrote:
Can someone who thinks this way, please explain why this is acceptable

[ x * x for x in some_iterator ]

But this is not

map(lambda x: x * x, some_iteraror)

and should be replaced with

def sqr(x): return x * x
map(sqr , some_iterator)


I guess I have similar feelings.

I've only been using python for a year or two, so I'm still a relative
newcomer.

Like a lot of people, I found Python to be magically simple and intuitive.

But I've never really found list comprehensions particularly clear. I don't
know whether it's my backgroud (mainly C/C++), or my brain or what, but they
are probably the only thing in Python that hasn't seemed transparent and
obvious to me (apart from shadowing of variables in nested functions).

Of course, I'm sure I could get used to them, given time. But that rather
defeats one of the main reasons for using python in the first place - the
lack of a steep learning curve.

In contrast, I find lambdas, even with their significant restrictions, to be
much more obvious. In fact, the proposal (sorry, don't have a link to hand)
about extending lambda to allow things like `myfn = def <indented block>' was
something that I initially assumed would become part of the language in time.

Is there some definitive information that explains why python is moving away
from lambdas and towards things like list comprehensions?

- Julian

--
http://www.op59.net/
Jul 18 '05 #29

P: n/a
"bruno modulix" <on***@xiludom.gro> wrote: in message news:42**********************@news.free.fr...
Ron wrote:
The problem here is that Kay's proposition mixes two points: flexible
tuple unpacking and a new syntax for anonymous functions.

Yes, two different problems. I don't think anything needs to be done
to tuples myself. I tend to use lists more anyway.


They are two different beasts. Note that you don't have anything like
list unpacking, now tuple unpacking is pretty common in Python (swap,
multiple return values, formatted strings and outputs, ...).


All the following are possible:
(x,y,z) = (1,2,3)
(x,y,z) = [1,2,3]
[x,y,z] = (1,2,3)
[x,y,z] = [1,2,3]


What exactly do you mean by "don't have anything like list unpacking" ?

George
Jul 18 '05 #30

P: n/a
Ron
On 23 Mar 2005 14:47:30 GMT, Duncan Booth
<du**********@invalid.invalid> wrote:
Kay Schluehr wrote:
A working makeVars seems not to be different from

def makeVars(**nameVals):
globals().update(nameVals)


Not quite. If Ron can come up with a working makeVars it would update the
caller's globals whereas what you just posted updates makeVar's globals so
there is a difference (when the makeVars and the calling function are in
different modules), just not a very useful one.


How about this one? The only reliable way I found to do it is to
pass locals() to the function.

def defvalue(**args):
args = args.items()
a1 = args[0]
a2 = args[1]
if type(a1[1]) == type({}):
vv, names = a2, a1[1]
else:
vv, names = a1, a2[1]
if names.has_key(vv[0]):
return names[vv[0]]
return vv[1]

f = defvalue(f=1, v=locals())
print f # 0

g = 19
g = defvalue(g=2, v=locals())
print g # 19

z = 6
def f1():
#z = 4
z = defvalue(z=3, v=locals())
print z
f1()

Jul 18 '05 #31

P: n/a
George Sakkis wrote:
"bruno modulix" <on***@xiludom.gro> wrote: in message news:42**********************@news.free.fr...

(snip)
Note that you don't have anything like
list unpacking, now tuple unpacking is pretty common in Python (swap,
multiple return values, formatted strings and outputs, ...).

All the following are possible:

(x,y,z) = (1,2,3)
(x,y,z) = [1,2,3]
[x,y,z] = (1,2,3)
[x,y,z] = [1,2,3]

What exactly do you mean by "don't have anything like list unpacking" ?


A stupidity :(

--
bruno desthuilliers
ruby -e "print 'on***@xiludom.gro'.split('@').collect{|p|
p.split('.').collect{|w| w.reverse}.join('.')}.join('@')"
Jul 18 '05 #32

P: n/a
Ron wrote:
A working makeVars seems not to be different from

def makeVars(**nameVals):
globals().update(nameVals)


Not quite. If Ron can come up with a working makeVars it would update
the caller's globals whereas what you just posted updates makeVar's
globals so there is a difference (when the makeVars and the calling
function are in different modules), just not a very useful one.


How about this one? The only reliable way I found to do it is to
pass locals() to the function.


Yes, but you are still missing the fundamental point. The locals()
dictionary is not guaranteed to do anything useful if you update it. The
current C implementation will reflect changes in the locals dictionary if
you call locals() from global scope or in a few other circumstances, but
this is simply an implementation detail.

If you want to update global variables then use globals() or setattr on the
module. Only use locals() to access local variables indirectly, never to
try and set them.
Jul 18 '05 #33

P: n/a
Ron
On 24 Mar 2005 09:20:52 GMT, Duncan Booth
<du**********@invalid.invalid> wrote:
Ron wrote:
A working makeVars seems not to be different from

def makeVars(**nameVals):
globals().update(nameVals)

Not quite. If Ron can come up with a working makeVars it would update
the caller's globals whereas what you just posted updates makeVar's
globals so there is a difference (when the makeVars and the calling
function are in different modules), just not a very useful one.
How about this one? The only reliable way I found to do it is to
pass locals() to the function.


Yes, but you are still missing the fundamental point. The locals()
dictionary is not guaranteed to do anything useful if you update it. The
current C implementation will reflect changes in the locals dictionary if
you call locals() from global scope or in a few other circumstances, but
this is simply an implementation detail.


Nope, Didn't miss the point. The functions return a value, not create
it from within.
If you want to update global variables then use globals() or setattr on the
module. Only use locals() to access local variables indirectly, never to
try and set them.


Good advise. :)

One of pythons weak points is it is sometimes difficult to 'monitor
and confirm' what is happening leading to confusing try/except
constructions.

Having the function is_defined() and if_not_defined() have the
advantage that they can be use in expressions where try/except can't.
And the source code could be more compact and more readable.

The disadvantage is the functions are quite a bit slower than
try/except, probably due to the function call over head.

If they were built in, they may be as fast as the try/except and there
wouldn't be issues with having to passing locals() or globals() name
dictionaries.
It's interesting that there is a whole is_"type"_() group of functions
in the inspect module, but not a is_defined(). Maybe I just haven't
found it yet.
#############

def if_not_defined(v, dv=None, lv=locals()):
if lv.has_key(v):
return lv[v]
return dv

def is_defined(v, lv=locals()):
if lv.has_key(v):
return True
False

# Shorten names and pass locals() with lambas for
# convenience. (This needs to be in the function
# where they are used or it will break.
# Another use for lamba! ;)

ifnd = lambda v, dv, lv=locals(): if_not_defined(v,dv,lv)
isa = lambda v, lv=locals(): is_defined(v, lv)

# Totally useless routine. ;)
import random
for n in range(10):

# Delete a random x,y,z coordinate to
# simulate an unreliable data source.
d = random.choice([1,2,3])
if d==1:
if isa('x'): del x
elif d==2:
if isa('y'): del y
else:
if isa('z'): del z

# Replace the missing variable with a random number.
r = int(random.random()*100)
x, y, z = ifnd('x',r), ifnd('y',r), ifnd('z',r)
print x, y, z

###########
Jul 18 '05 #34

P: n/a
Ron wrote:
It's interesting that there is a whole is_"type"_() group of functions
in the inspect module, but not a is_defined(). Maybe I just haven't
found it yet.
I've never found any need for an is_defined function. If in doubt I just
make sure and initialise all variables to a suitable value before use.
However, I'll assume you have a good use case.


#############

def if_not_defined(v, dv=None, lv=locals()):
if lv.has_key(v):
return lv[v]
return dv
I don't see the point of the default argument. locals() at the global level
simply returns globals, so you might as well use that. A more useful
default would be the caller's locals.

def is_defined(v, lv=locals()):
if lv.has_key(v):
return True
False
Same comments, plus the whole 'if on a boolean to return a boolean' is a
bit redundant.

Try something on these lines:
import inspect
def is_defined(name, lv=None): if lv is None:
lv = inspect.currentframe().f_back.f_locals
return name in lv
is_defined('abc') False abc = 3
is_defined('abc') True def f(x): print is_defined('x')
print is_defined('y')
y = 0
print is_defined('y')

f(2)

True
False
True

# Shorten names and pass locals() with lambas for
# convenience. (This needs to be in the function
# where they are used or it will break.
# Another use for lamba! ;)

ifnd = lambda v, dv, lv=locals(): if_not_defined(v,dv,lv)
isa = lambda v, lv=locals(): is_defined(v, lv)


There is no need for lambda here, it adds nothing. Use a 'def'.

Jul 18 '05 #35

P: n/a
On 25 Mar 2005 10:09:50 GMT, Duncan Booth
<du**********@invalid.invalid> wrote:

I've never found any need for an is_defined function. If in doubt I just
make sure and initialise all variables to a suitable value before use.
However, I'll assume you have a good use case.


I admit that that is the better practice. George's example was the
conversion of data from one form to another where the data is mixed
with complete and incomplete items. And Kay is looking at tuple
unpacking.

It's hard to beat try/except for these situations though. :)

I cleaned it up some more and figured out the proper use of
_getframe(). So no lambdas, and no passing of locals needed., and it
checks for globals and builtins before defining the default value so
as not to over write a readable value.

I'm not sure what the best behavior should be. Maybe a routine to
tell where a name is, ie.. local, global, builtin, or a writable
global? maybe isa() return the location or None.? I think that would
be better.

The best purpose for utilities like these is for debugging and getting
feedback about the environment. So I'm thinking of putting them in a
module for that purpose. I have a subroutine to list all the names
attached to an object. I think I can add that a bit now too.
#---Here's the code---------------------

import sys

def isa(v):
"""
Check if a varable exists in the current
(parent to this function), global, or
builtin name spaces.

use: bool = isa( str )
returns True or False
"""
plocals = sys._getframe(1).f_locals
if plocals.has_key(v) or globals().has_key(v) or \
__builtins__.locals().has_key(v):
return True
return False
def ifno(v, obj=None):
"""
Check if a varable does not exists, return a
default value, otherwise return the varable obj.

use: obj = ifno( str [,obj=None] )
if str exist, returns str's object
if str does not exist, returns specified object
"""
plocals = sys._getframe(1).f_locals
if plocals.has_key(v):
return plocals[v]
if globals().has_key(v):
return globals()[v]
if __builtins__.locals().has_key(v):
return __builtins__.locals()[v]
return obj
def test():
"""
Test isa() and ifno() functions:
"""

# Totally useless routine. ;)
import random
for n in range(25):

# Delete a random x,y,z coordinate to
# simulate an unrealiabe data source.
d = random.choice([1,2,3])
if d==1:
if isa('x'): del x
elif d==2:
if isa('y'): del y
else:
if isa('z'): del z

# Replace the missing Varible with a random number.
r = int(random.random()*100)
x, y, z = ifno('x',r), ifno('y',r), ifno('z',r)
print x, y, z
if __name__ == '__main__':
test()

#-------------------------------------
Jul 18 '05 #36

P: n/a
"Ron_Adam" <ra****@tampabay.rr.com> wrote:
On 25 Mar 2005 10:09:50 GMT, Duncan Booth
<du**********@invalid.invalid> wrote:

I've never found any need for an is_defined function. If in doubt I just
make sure and initialise all variables to a suitable value before use.
However, I'll assume you have a good use case.


I admit that that is the better practice. George's example was the
conversion of data from one form to another where the data is mixed
with complete and incomplete items. And Kay is looking at tuple
unpacking.

It's hard to beat try/except for these situations though. :)


I posted a recipe in python cookbook
(http://aspn.activestate.com/ASPN/Coo.../Recipe/392768) for the subproblem I was interested
in initially (variable-length iterable unpacking), and I prefer it over explicit try/except (but of
course I'm biased :-)). Kay is proposing something even more general and powerful, and it will be
interesting to see if all this brainstorming can be brought forward more 'formally', e.g. at a PEP
or pre-PEP level.

Regards,
George
Jul 18 '05 #37

P: n/a
On Fri, 25 Mar 2005 17:09:38 -0500, "George Sakkis"
<gs*****@rutgers.edu> wrote:
I posted a recipe in python cookbook
(http://aspn.activestate.com/ASPN/Coo.../Recipe/392768) for the subproblem I was interested
in initially (variable-length iterable unpacking), and I prefer it over explicit try/except (but of
course I'm biased :-)). Kay is proposing something even more general and powerful, and it will be
interesting to see if all this brainstorming can be brought forward more 'formally', e.g. at a PEP
or pre-PEP level.

Regards,
George


Looks good George. :)

I'm not sure what Kay is trying for, but it does look interesting. I'm
all for new features as long as they are consistent and easy to use,
and easy to remember as well. I keep finding ways to improve the
little routines I'm playing with. ;) I'll probably post them in the
cookbook also, and maybe put them together in a mod.

A few more pieces and I should be able to build a name space explorer
which I think will be good for debugging programs. I'm thinking you
could put it in the program where you are having problems and it will
open a tree type window where you can examine all the names and
objects at that point. When done, close it and the programs
continues. It will give you a little more info than sticking print
statements hear and there.

Ron

Jul 18 '05 #38

This discussion thread is closed

Replies have been disabled for this discussion.