annonymous functions -- how to

M

Mayer

Hello:

I would like to define a very large annonymous function, one with
several statements in sequence. I know how to define annonymous
functions, but I don't know how to define a sequence of statements in
their body. Can this be done in Python? If so, how?

Thanks,

Mayer
 
P

Peter Otten

Mayer said:
I would like to define a very large annonymous function, one with
several statements in sequence. I know how to define annonymous
functions, but I don't know how to define a sequence of statements in
their body. Can this be done in Python? If so, how?

No, it can't. Why do you prefer your function to be anonymous?

Peter
 
B

Bengt Richter

No, it can't. Why do you prefer your function to be anonymous?
Depends on what you mean by "anonymous" ;-)
... print 'statement 1'
... print 'statement 2'
... print 'statement etc'
...
>>> foo.__name__ = '' # make really anonymous
>>> fooholder = [foo]
>>> del foo # forget name binding too
>>> dir() ['__builtins__', '__doc__', '__name__', 'fooholder']
>>> fooholder.append(lambda: 'not that anonymous ;-)')
>>> fooholder
>>> [f.__name__ for f in fooholder]
['' said:
>>> fooholder[0](), fooholder[1]()
statement 1
statement 2
statement etc
(None, 'not that anonymous ;-)')

Regards,
Bengt Richter
 
J

Jason Mobarak

What's wrong with:

def blah():
def _ (a, b, c):
a = a + 2
print "stmt 2"
return a+b/c
return doSomethingWith(_)

It's basically "anonymous", it just uses a name that you don't care
about. AFAIK, it can be immediately clobbered later if need be.
Otherwise, the function shouldn't be anonymous.
 
P

Peter Hansen

Jason said:
What's wrong with:

def blah():
def _ (a, b, c):
a = a + 2
print "stmt 2"
return a+b/c
return doSomethingWith(_)

It's basically "anonymous", it just uses a name that you don't care
about. AFAIK, it can be immediately clobbered later if need be.
Otherwise, the function shouldn't be anonymous.

Or even better:

def blah():
def doJasonsAlgorithm(a, b, c):
a = a + 2
print "stmt 2"
return a+b/c
return doSomethingWith(doJasonsAlgorithm)

That way you've got reasonably self-documenting code, and don't have to
face an annoyed maintainer saying "what a jerk: he didn't comment this
or even give it a useful name... idiot... grumble grumble."

I doubt there's a valid usecase for a "anonymous" function that has more
than a line or two. Personally, I don't think there's a good usecase
for an anonymous function longer than one line...

-Peter
 
D

Dave Benjamin

Peter said:
I doubt there's a valid usecase for a "anonymous" function that has more
than a line or two. Personally, I don't think there's a good usecase
for an anonymous function longer than one line...

The case that I keep running into regards event-driven programming. I
need to do a series of operations that are tied together asynchronously
via callback functions, but I still want the actions to read in-order.
With anonymous functions (and I mean the ones that you can use within
expressions, Bengt ;) ), I could write something like the following:

def add_thingy():
with_next_thingy_id(def(thingy_id):
print 'got thingy id:', thingy_id
with_next_doodad_id(def(doodad_id):
pring 'got doodad id:', doodad_id
with_new_thingy_doodad(thingy_id, doodad_id,
def(thingy_doodad):
print 'thingy doodad created, froobling...'
frooble(thingy_doodad)
print 'froobling complete'
)
)
)

In this case, having to name these callback functions is tiring and
awkward, and (IMHO) disrupts the flow of my function:

def add_thingy():
def next_thingy_id_func(thingy_id):
print 'got thingy id:', thingy_id
def next_doodad_id_func(doodad_id):
print 'got doodad id:', doodad_id
def new_thingy_doodad_func(thingy_doodad):
print 'thingy doodad created, froobling...'
frooble(thingy_doodad)
print 'froobling complete'
with_new_thingy_doodad(thingy_id, doodad_id,
new_thingy_doodad_func)
with_next_doodad_id(next_doodad_id_func)
with_next_thingy_id(next_thingy_id_func)

There is no reason why these callbacks would necessarily be one-liners
or ten-liners. I suppose this problem could be solved by defining all
the functions at the top-level (or by using bound methods of an object),
but to me this is harder to maintain and doesn't read as well.

Not life or death, but there's at least one use case that I would at
least consider "valid". Your definition of "valid" may differ, of course. =)

Dave
 
B

Bengt Richter

Or even better:

def blah():
def doJasonsAlgorithm(a, b, c):
a = a + 2
print "stmt 2"
return a+b/c
return doSomethingWith(doJasonsAlgorithm)

That way you've got reasonably self-documenting code, and don't have to
face an annoyed maintainer saying "what a jerk: he didn't comment this
or even give it a useful name... idiot... grumble grumble."

I doubt there's a valid usecase for a "anonymous" function that has more
than a line or two. Personally, I don't think there's a good usecase
for an anonymous function longer than one line...
Yes, but only the BDFL can outlaw things on that kind of basis ;-)

My post was just to play with "anonymous" a little, not to motivate
more examples of strange call layering and dynamic execution of defs
that don't change etc. ;-)

BTW, I view a def as a kind of assignment statement with the target restricted
to a local bare name. I.e.,

def foo(): pass # def <restricted assignment target>():pass

So why have this form of assignment? And why restrict it to a bare name, even
if you want to keep the def for mnemonic convention to use as usual?

I.e., why not loosen def to allow e.g.

def MyClass.method(self): pass
or
@staticmethod
def MyClass.square(x): return x*x

or
def fdict['sqr'](x): return x*x

Well, I can see a reason not to do the last that way. It would be much clearer using
an anonymous def, e.g.,

fdict['sqr'] = def(x): return x*x

And then you can say lambda is fine for that, except for the limitation
that the body be just an expression. Then you might ask, why not bend that a little? E.g.,

fdict['sqrt'] = def(x):
if x < 0: raise ValueError, 'x must be non-negative, not %r' %x
return math.sqrt(x)

And then, why not allow an anonymous defs as expressions anywhere expressions can go?
(indentation problems are actually easy to overcome).

Anyway, in general, I'd rather be persuaded than forced ;-)

Regards,
Bengt Richter
 
F

Fredrik Lundh

Dave said:
In this case, having to name these callback functions is tiring and
awkward, and (IMHO) disrupts the flow of my function:

so name them all "func" or "next" or something, so you don't have
to think. once the object is bound, the name is irrlevant.
def add_thingy():
def next_thingy_id_func(thingy_id):
print 'got thingy id:', thingy_id
def next_doodad_id_func(doodad_id):
print 'got doodad id:', doodad_id
def new_thingy_doodad_func(thingy_doodad):
print 'thingy doodad created, froobling...'
frooble(thingy_doodad)
print 'froobling complete'
with_new_thingy_doodad(thingy_id, doodad_id,
new_thingy_doodad_func)
with_next_doodad_id(next_doodad_id_func)
with_next_thingy_id(next_thingy_id_func)

there's also:

def add_thingy(self):

yield get_new_thingy_id; thingy_id = self.result

print 'got thingy id:', thingy_id

yield get_new_doodad_id; doodad_id = self.result

print 'got doodad id:', doodad_id

yield get_new_thingy_doodad; thingy_doodad = self.result

print 'thingy doodad created, froobling...'
frooble(thingy_doodad)
print 'froobling complete'

</F>
 
S

Scott David Daniels

Fredrik said:
so name them all "func" or "next" or something, so you don't have
to think. once the object is bound, the name is irrlevant.
Or, you could tell him about the reserved word anonymous which can be
used to created unnamed functions of values. A sample definition and
use of the anonymous keyword follows:

def anonymous(text):
return 'modified ' + text

print 'Sample', anonymous('words')

--Scott David Daniels (with his tongue jammed firmly in his cheek)
(e-mail address removed)
 
D

Dave Benjamin

Fredrik said:
so name them all "func" or "next" or something, so you don't have
to think. once the object is bound, the name is irrlevant.

Sure, you could do this, but then you'd have multiple functions at
different nesting levels with the same name, which would be confusing.
You could call them "func1", "func2", "func3", and so on, but at this
point it becomes painfully obvious that you really don't care what the
names are; you're only naming them because you have to. As Paul Graham
would say, it's "the human compiler at work".
there's also:

def add_thingy(self):

What object is "self"? Are we defining a method at this point?
yield get_new_thingy_id; thingy_id = self.result

What is "get_new_thingy_id"? A function? To whom are we yielding here?

Dave
 
F

Fredrik Lundh

Dave said:
Sure, you could do this, but then you'd have multiple functions at
different nesting levels with the same name, which would be confusing.

"I don't wanna try that", you mean.

because if you had done so, you would have noticed that "multiple
functions with the same name" doesn't have to be any more confusing
than "multiple print statements" or "multiple if statements" (as long as
you're not using bad names on purpose, of course).
What object is "self"? Are we defining a method at this point?

if you have a problem with methods, you shouldn't use Python.
What is "get_new_thingy_id"? A function? To whom are we yielding here?

I could have sworn that you mentioned event-driven programming
in your original post. if that's still what you're doing, the answers
are "a token" and "the event source".

</F>
 
D

Dave Benjamin

Fredrik said:
"I don't wanna try that", you mean.

No, I mean, "I have an imagination". But for the sake of argument, here,
I'll try that:

def add_thingy():
def func(thingy_id):
print 'got thingy id:', thingy_id
def funnc(doodad_id):
print 'got doodad id:', doodad_id
def func(thingy_doodad):
print 'thingy doodad created, froobling...'
frooble(thingy_doodad)
print 'froobling complete'
with_new_thingy_doodad(thingy_id, doodad_id, func)
with_next_doodad_id(func)
with_next_thingy_id(func)

This function now has an infinite loop. Can you spot the reason?
because if you had done so, you would have noticed that "multiple
functions with the same name" doesn't have to be any more confusing
than "multiple print statements" or "multiple if statements" (as long as
you're not using bad names on purpose, of course).

I have noticed. It is more confusing. That's the whole point.
if you have a problem with methods, you shouldn't use Python.

No, I was asking you to clarify, are we rewriting "add_thingy" to be a
method, and if so, what class is it a method of, and what are its
responsibilities? Because it seems like this example now shares data
through an instance, but this data is not required for any other method,
so it will add clutter to the instance namespace. If anything, it seems
that "add_thingy" should be moved into another class at this point, in
which case it follows that every method that needs to do this sort of
asynchronous communication would likewise be moved to a new class. This
is fine, I suppose, but it's a lot more verbose.
I could have sworn that you mentioned event-driven programming
in your original post. if that's still what you're doing, the answers
are "a token" and "the event source".

I am just trying to make sense of your example. I am still talking about
event-programming. Here are the events:

1. Program A sends program B a message, saying, "I need a thingy ID".
2. B sends A a message, "Here's a thingy ID: 42".
3. A sends B a message, "I need a doodad ID".
4. B sends A a message, "Here's a doodad ID: 43".
5. A sends B a message, "Make a thingy doodad with IDs 42 and 43".
6. B sends A a message, "Thingy doodad created".
7. A sends B a message, "Now, frooble the thingy doodad".

I don't know what parts of this transcript you would consider "tokens".
And I'm also not sure how generators can provide an alternative solution
to this problem. I am genuinely interested.

Dave
 
P

Peter Hansen

Dave said:
def add_thingy():
def func(thingy_id):
print 'got thingy id:', thingy_id
def funnc(doodad_id):
print 'got doodad id:', doodad_id
def func(thingy_doodad):
print 'thingy doodad created, froobling...'
frooble(thingy_doodad)
print 'froobling complete'
with_new_thingy_doodad(thingy_id, doodad_id, func)
with_next_doodad_id(func)
with_next_thingy_id(func)

This function now has an infinite loop. Can you spot the reason?

Not offhand, and to be completely honest, the original with the longer
names was equally unreadable. I doubt this is the best way to do
whatever the heck it is that this is supposed to do.

Oh, and while I was typing my eyes fell on "funnc" misspelled above.
Presumably that's your loop...

Spelling "func" as "_" would tend to avoid this as well, unless you have
a keyboard that repeats keys accidentally.

-Peter
 
D

Dave Benjamin

Peter said:
Not offhand, and to be completely honest, the original with the longer
names was equally unreadable. I doubt this is the best way to do
whatever the heck it is that this is supposed to do.

I agree. I think both are difficult to read. I find the first version
that I originally posted (using an imaginary anonymous function syntax)
much easier to understand.

I think I've made it pretty clear what this is supposed to do in my
earlier post to Fredrik, delineating each step of the communication
process. If you have a better way to do this, I'd certainly like to see it.
Oh, and while I was typing my eyes fell on "funnc" misspelled above.
Presumably that's your loop...

Yes, precisely. And because of a typo, the wrong callback gets passed,
causing it to use the same callback over and over. With anonymous
functions, there would be nothing to name, and therefore, nothing to
misspell.
Spelling "func" as "_" would tend to avoid this as well, unless you have
a keyboard that repeats keys accidentally.

Hrmmm. Well, it is less to type.

Dave
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top