if __name__ == '__main__':
root = Tkinter.Tk()
w = Tkinter.Button(root, text='This is a very green button', width= 30, fg='green')
buttonList = (
['show', lambda x = w: x.grid(row=0, col=0, columnspan= 5)],
['pink', lambda x = w: x.configure(fg='pink')],
['yellow', lambda x = w: x.configure(bg='yellow')],
['Exit', root.destroy],
)
column = 0
for txt, cmd in buttonList:
button = Tkinter.Button(root, text = txt, command = cmd)
button.grid(row=1, col=column, sticky = 'w')
column = column + 1
root.mainloop()
If I had just used w.grid up there I would get a yellow button with pink
text. This form is concise. What do the lambda dislikers suggest I do
instead? (This is a serious question)
Laura Creighton
I use it quite a bit in similar situations, e.g. when using
nested loops to create a matrix of buttons, each of which has a
command function that must know the column/row number.
--
Grant Edwards grante Yow! Now that I have my
at "APPLE," I comprehend COST
visi.com ACCOUNTING!!
>I use lambda for things like this:
>
>if __name__ == '__main__':
> root = Tkinter.Tk()
> w = Tkinter.Button(root, text='This is a very green button', width= 30, fg='green')
>
> buttonList = (
> ['show', lambda x = w: x.grid(row=0, col=0, columnspan= 5)],
> ['pink', lambda x = w: x.configure(fg='pink')],
> ['yellow', lambda x = w: x.configure(bg='yellow')],
> ['Exit', root.destroy],
> )
> column = 0
> for txt, cmd in buttonList:
> button = Tkinter.Button(root, text = txt, command = cmd)
> button.grid(row=1, col=column, sticky = 'w')
> column = column + 1
> root.mainloop()
lambda is cool!
Why not to use it in map and drop for-loop also?
map(lambda (txt, cmd), column, root=root:
Tkinter.Button(root, text = txt, command = cmd).
grid(row=1, col=column, sticky = 'w'),
buttonList, range(len(buttonList)))
(I have not checked if this works, but looks fine)
>If I had just used w.grid up there I would get a yellow button with pink
>text. This form is concise. What do the lambda dislikers suggest I do
>instead? (This is a serious question)
>
>Laura Creighton
>
>
Sincerely yours, Roman Suzi
--
_/ Russia _/ Karelia _/ Petrozavodsk _/ r...@onego.ru _/
_/ Wednesday, May 23, 2001 _/ Powered by Linux RedHat 6.2 _/
_/ "Never mind the facts - I know what I know." _/
yep, neat.
...but how 'bout this:
buttonList = (
['show', curry(w.grid, row=0, col=0, columnspan= 5)],
['pink', curry(w.configure, fg='pink')],
['yellow', curry(w.configure, bg='yellow')],
['Exit', root.destroy],
)
(curry.py is in the cookbook)
The named-function approach would be no less concise here:
def show(): w.grid(row=0, col=0, columnspan=5)
def pink(): w.configure(fg='pink')
def yellow(): w.configure(bg='yellow')
def Exit(): root.destroy()
buttonList = show, pink, yellow, Exit
column = 0
for act in buttonList:
button=Tkinter.Button(root, text=act.__name__, command=act)
button.grid(row=1, col=column, sticky='w')
column += 1
root.mainloop()
Concision-promoting nested scopes and += help, but I think you
do save a couple characters anyway -- haven't bothered counting:-).
Seriously, the peculiarity here is that all of the button-texts
are acceptable as local function-names, so the def statements
play a dual role: define the codeblock to be run as the command
AND the name that codeblock goes by, to show on the button. As
soon as you needed to have a button show text such as
'pink fg'
or
'yellow bg'
i.e. with a space inside, or anything but ASCII alphanumerics,
this wouldn't generalize -- you'd have to separately record
up to TWO 'names' for each action, in this case. For example,
the buttonList might have to be defined as:
buttonList = show, (pink, 'pink fg'), yellow, (root.destroy, 'Exit')
and the loop would be:
for act in buttonList:
try: cmd, txt = act
except: cmd = act; txt = act.__name__
button = Tkinter.Button(root, text=txt, command=cmd)
etc -- where I've also taken advantage of cases in which you
DO have a ready no-arguments callable such as root.destroy
to use, since now you don't need to wrap it into a function
JUST to change the button-text. Some would think this a
"tricky" approach in some ways, but it seems reasonable
style to me.
OTOH, the lambda approach doesn't generalize without refactoring
on ANOTHER axis -- that of needing more than just an expression
as a button's action... when in the course of development or
maintenance it turns out that, e.g., "yellow" also needs to
increment a "global yellow count" each time it's clicked, the
lambda approach does require you to substitute a named local
function instead, while this function-approach affords more
immediate localized refactoring -- just change the function
body for the existing 'def yellow():'.
I understand and respect the argument "as long as we have
lambda in the language, migth as well make use of it", at
least in cases where its strong limitations don't byte (or
not too badly:-). But, in my personal opinion, using
named (local) functions instead of lambda is not really
a big problem -- it may have pluses and minuses, but the
minuses tend to be smaller than the pluses in practice
(in my limited experience... I hardly ever code lambdas
these days, having gotten into the habit of naming my
functions anyway:-). Again IMHO, the language would be
(marginally) better off without lambda, which does not
"fully carry its weight" (maybe it would, alternatively,
be better off with a _more powerful_ lambda, able to
express a block of statements rather than just an
expression, but I do not know if the resulting complexity
would have a net positive return). Not having lambda
would promote the "one obvious way to do it" mantra:-).
I don't consider the issue a major one either way... no
doubt NOT worth the hassle of a backwards incompatibility!-)
Alex
If you are using Python 2.1, then the lambda form becomes much neater:
from __future__ import nested_scopes
import Tkinter
if __name__ == '__main__':
root = Tkinter.Tk()
w = Tkinter.Button(root, text='This is a very green button', width= 30,
fg='green')
buttonList = (
['show', lambda: w.grid(row=0, col=0, columnspan= 5)],
['pink', lambda: w.configure(fg='pink')],
['yellow', lambda: w.configure(bg='yellow')],
['Exit', root.destroy],
)
column = 0
for txt, cmd in buttonList:
button = Tkinter.Button(root, text = txt, command = cmd)
button.grid(row=1, col=column, sticky = 'w')
column = column + 1
root.mainloop()
--
Duncan Booth dun...@rcp.co.uk
int month(char *p){return(124864/((p[0]+p[1]-p[2]&0x1f)+1)%12)["\5\x8\3"
"\6\7\xb\1\x9\xa\2\0\4"];} // Who said my code was obscure?
...but so does the named-function form, equally -- see my latest
post in this thread. Nested scopes apply in just the same way to
lambda's and to normal (named) nested functions.
As was noted in another post, nested scopes don't let you REBIND
the local variables of the function you're nested in -- lambdas
can't rebind anything anyhow, of course -- well I guess one COULD
use an elegant and readable construct such as:
lambda x: setattr(sys.module[__name__], 'k', k+x) or k
to get an unnamed equivalent of
def adder(x):
global k
k += x
return k
but then the PSU might
If counters are so common in the application in question, why not to:
class counter:
def __init__(self, start=0):
self._counter = start
def __call__(self, delta=1):
self._counter = self._counter + delta
return self._counter
bc = counter()
lambda x, ...: F(bc(x), ...) # where F() does something useful
Counter logic may be more complicated than just addition. For example,
counting Parts, Chapters, etc of a book could be more complex. Even LaTeX
has special macros for counters.
Its more safe to have global objects than global counters. I had
situations where I messed things up because of global variables. That is
why I think counters must be part of the object, where counting occurs:
this way one may be sure about counter's initialization and such.
For example, I have a script to index thumbernails of images (it also
counts them of course.) And I had an error in it when I forgot to
initialize counters/data accumulators before processing next web-page...
> to get an unnamed equivalent of
>
> def adder(x):
> global k
> k += x
> return k
>
> but then the PSU might
Sincerely yours, Roman A.Suzi
--
- Petrozavodsk - Karelia - Russia - mailto:r...@onego.ru -
> from __future__ import nested_scopes
> import Tkinter
>
> if __name__ == '__main__':
> root = Tkinter.Tk()
> w = Tkinter.Button(root, text='This is a very green button', width= 30,
> fg='green')
>
> buttonList = (
> ['show', lambda: w.grid(row=0, col=0, columnspan= 5)],
> ['pink', lambda: w.configure(fg='pink')],
> ['yellow', lambda: w.configure(bg='yellow')],
> ['Exit', root.destroy],
> )
Actually, the same works in any Python version since lambda was
introduced: w is a global variable, and determined as a global in each
of the lambda functions, so you don't need future nested scopes here.
Regards,
Martin