Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #55642 > unrolled thread

Parameterized functions of no arguments?

Started byRotwang <sg552@hotmail.co.uk>
First post2011-02-11 04:54 +0000
Last post2011-02-11 05:26 +0000
Articles 6 — 5 participants

Back to article view | Back to comp.lang.python


Contents

  Parameterized functions of no arguments? Rotwang <sg552@hotmail.co.uk> - 2011-02-11 04:54 +0000
    Re: Parameterized functions of no arguments? Hrvoje Niksic <hniksic@xemacs.org> - 2011-02-11 15:43 +0100
    Re: Parameterized functions of no arguments? Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2011-02-10 23:22 -0800
    Re: Parameterized functions of no arguments? Carl Banks <pavlovevidence@gmail.com> - 2011-02-11 05:59 +0000
    Re: Parameterized functions of no arguments? Chris Rebert <clp2@rebertia.com> - 2011-02-10 21:50 -0800
    Re: Parameterized functions of no arguments? Rotwang <sg552@hotmail.co.uk> - 2011-02-11 05:26 +0000

#55642 — Parameterized functions of no arguments?

FromRotwang <sg552@hotmail.co.uk>
Date2011-02-11 04:54 +0000
SubjectParameterized functions of no arguments?
Message-ID<ij2fdr$uo7$1@news.eternal-september.org>
Hi all

Sorry if this is a dumb question, I would guess it's answered in an FAQ 
somewhere but I haven't been able to find anything that helps. I'm 
trying to use Tkinter to create a menu whose entries and corresponding 
commands depend on some list x. I want the menu options to be labelled 
by the elements of x, and upon selecting an option k I want my program 
to execute a function f(k). So I tried writing something that 
schematically looked like this:

     def f(k):
         [do something that depends on k]

     menu = Tkinter.Menu(master, tearoff = 0)
     for k in x:
         menu.add_command(label = str(k), command = lambda: f(k))

The trouble is, whenever I open the menu and click on any entry k, 
instead of evaluating f(k) it always evaluates f(x[-1]). I've also tried 
this:

     menu = Tkinter.Menu(master, tearoff = 0)
     for k in x:
         def f():
             [do something that depends on k]
         menu.add_command(label = str(k), command = f)

and it gives me the same problem. Can anybody suggest a way around this?

[toc] | [next] | [standalone]


#55699

FromHrvoje Niksic <hniksic@xemacs.org>
Date2011-02-11 15:43 +0100
Message-ID<87bp2izl6a.fsf@xemacs.org>
In reply to#55642
Chris Rebert <clp2@rebertia.com> writes:

> It's a well-known problem due to the intricacies of Python's scoping
> rules.

Actually, it is not specific to Python's scoping rules (which mandate
local, then module-level, then built-in name lookup).  The root of the
surprise is, as you correctly point out, the fact that the variable's
"cell" is shared by all iterations through the loop.  Taking that into
account, it logically follows that all enclosed functions end up reading
the same value.

This is not endemic to Python, the exact same surprise is present in
Common Lisp, a language with long tradition of closures and otherwise
radically different scoping rules.

* (setq l (loop for i from 1 to 10 collect (lambda () i)))
* (mapcar #'funcall l)
(11 11 11 11 11 11 11 11 11 11)

[toc] | [prev] | [next] | [standalone]


#55728

FromDennis Lee Bieber <wlfraed@ix.netcom.com>
Date2011-02-10 23:22 -0800
Message-ID<mailman.93.1297408937.1633.python-list@python.org>
In reply to#55642
On Fri, 11 Feb 2011 04:54:11 +0000, Rotwang <sg552@hotmail.co.uk>
declaimed the following in gmane.comp.python.general:

>          menu.add_command(label = str(k), command = lambda: f(k))
>

	I'm not sure, but what effect does

		menu.add_command(label=str(k), command = lambda k=k: f(k))

have on the processing.

	Confusing syntax, I know... does it make more sense as 
			... lambda x=k: f(x)...

-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
        wlfraed@ix.netcom.com    HTTP://wlfraed.home.netcom.com/

[toc] | [prev] | [next] | [standalone]


#56019

FromCarl Banks <pavlovevidence@gmail.com>
Date2011-02-11 05:59 +0000
Message-ID<ij2j82$a8u$1@news.eternal-september.org>
In reply to#55642
Rotwang wrote:
> On 11/02/2011 04:54, Rotwang wrote:
> Mmmmnngh, that obviously wasn't going to work. Here's something that 
> does work:
>
>      menu = Tkinter.Menu(master, tearoff = 0)
>      for k in x:
>          def f(j = k):
>              [do something that depends on j]
>          menu.add_command(label = str(k), command = f)
>
> Still, I'd like to know if there's a more elegant method for creating a 
> set of functions indexed by an arbitrary list.

If you don't want to use keyword arguments you can define a helper
function to help create your closure:

def create_menu_command(j):
    def f():
        do_something_that_depends_on(j)
    return f

for k in x:
    menu.add_command(label=str(k),command=create_menu_command(k))


Carl Banks

[toc] | [prev] | [next] | [standalone]


#56025

FromChris Rebert <clp2@rebertia.com>
Date2011-02-10 21:50 -0800
Message-ID<mailman.91.1297403413.1633.python-list@python.org>
In reply to#55642
On Thu, Feb 10, 2011 at 8:54 PM, Rotwang <sg552@hotmail.co.uk> wrote:
> Hi all
>
> Sorry if this is a dumb question, I would guess it's answered in an FAQ
> somewhere but I haven't been able to find anything that helps. I'm trying to
> use Tkinter to create a menu whose entries and corresponding commands depend
> on some list x. I want the menu options to be labelled by the elements of x,
> and upon selecting an option k I want my program to execute a function f(k).
> So I tried writing something that schematically looked like this:
>
>    def f(k):
>        [do something that depends on k]
>
>    menu = Tkinter.Menu(master, tearoff = 0)
>    for k in x:
>        menu.add_command(label = str(k), command = lambda: f(k))
>
> The trouble is, whenever I open the menu and click on any entry k, instead
> of evaluating f(k) it always evaluates f(x[-1]). I've also tried this:
>
>    menu = Tkinter.Menu(master, tearoff = 0)
>    for k in x:
>        def f():
>            [do something that depends on k]
>        menu.add_command(label = str(k), command = f)
>
> and it gives me the same problem. Can anybody suggest a way around this?

It's a well-known problem due to the intricacies of Python's scoping rules.
One workaround is:

for k in x:
    def f(k=k):
[rest same as before]

Basically, the problem is that f() does close over the variable k, but
not the particular value of k at the time it was defined; f() looks up
the value of k anew each time it's called. But by the time you get
around to actually calling f(), the loop has terminated and thus k
retains its last value of x[-1]. Default argument values, however, are
evaluated only once and at definition-time, thus achieving the
intended behavior.

Cheers,
Chris
--
http://blog.rebertia.com

[toc] | [prev] | [next] | [standalone]


#56034

FromRotwang <sg552@hotmail.co.uk>
Date2011-02-11 05:26 +0000
Message-ID<ij2ha2$kss$1@news.eternal-september.org>
In reply to#55642
On 11/02/2011 04:54, Rotwang wrote:
> Hi all
>
> Sorry if this is a dumb question, I would guess it's answered in an FAQ
> somewhere but I haven't been able to find anything that helps. I'm
> trying to use Tkinter to create a menu whose entries and corresponding
> commands depend on some list x. I want the menu options to be labelled
> by the elements of x, and upon selecting an option k I want my program
> to execute a function f(k). So I tried writing something that
> schematically looked like this:
>
>     def f(k):
>         [do something that depends on k]
>
>     menu = Tkinter.Menu(master, tearoff = 0)
>     for k in x:
>         menu.add_command(label = str(k), command = lambda: f(k))
>
> The trouble is, whenever I open the menu and click on any entry k,
> instead of evaluating f(k) it always evaluates f(x[-1]). I've also tried
> this:
>
>     menu = Tkinter.Menu(master, tearoff = 0)
>     for k in x:
>         def f():
>             [do something that depends on k]
>         menu.add_command(label = str(k), command = f)


Mmmmnngh, that obviously wasn't going to work. Here's something that 
does work:

     menu = Tkinter.Menu(master, tearoff = 0)
     for k in x:
         def f(j = k):
             [do something that depends on j]
         menu.add_command(label = str(k), command = f)

Still, I'd like to know if there's a more elegant method for creating a 
set of functions indexed by an arbitrary list.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web