Using lambda function within event binding

Thanks, Cody, that’s exactly what I was looking for. And after I saw
that, I discovered the reason that the non-gui version happened to
work. So the problem was entirely in my understanding of lambda, not
anything to do with wxPython. That extra index argument was coming
from whatever the current value is of the init function’s local
variable i. I was able to show that by adding another assignment to i,
following the loop.

So, now the question is: how can I learn more about lambda? In
working with at least 35 languages over the past 40 years, I’ve never
had such a capability before, and I need to understand its limits. Of
course, lambda is just a special case of the more general notion of
functions as real objects. In every other language I’ve known, a
function had state only while it was executing, and that state was on
the stack. But Python offers at least three ways for functions to have
multiple instances, each containing separate state information:
lambda, callable class objects, and generators.

So far, my working theory is that the only state the function contains
before it begins executing is the default arguments, which are
evaluated when the function is compiled. And the non-argument
externals referenced within the function are resolved into ‘references’
not values, at compile time. In a compiled language without nested
functions, the difference is moot, but here it is significant.

In C++, when I didn’t understand a concept, I’d look at the generated
machine code, and see what was happening. (It didn’t help much when
the compiler didn’t match the language definition, but it usually did.)
And I also knew folks on the C++ ANSI standards comittee. And
eventually I was parading in the depths of the generated intermediate
code from the compiler. But Python still has several concepts that
elude me, and I don’t know where to see the detailed descriptions, nor
do I seem to have tools that let me examine what’s really happening.

My self-assignment for this afternoon: “Programming Python” by Mark
Lutz, 3rd edition, starting with pag 390 (‘Passing in values with
default arguments’, ‘Passing in values with enclosing scope
references’, …) Although I’ve been through it before, maybe this
time it’ll begin making sense.

···
  class MouseEventFrame(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id, title="Testing", size=(300, 120))
self.panel = wx.Panel(self)
for i in range(3):
self.button = wx.Button(self.panel, label="Button "+str(i), pos=(100, 15 + 20*i ))
self.Bind(wx.EVT_BUTTON, lambda evt : self.OnSetRank(evt, i), self.button)

try:
self.Bind(wx.EVT_BUTTON, lambda evt, index=i: self.OnSetRank(evt, index), self.button)
Cody

Dave Angel wrote:

So the problem was entirely in my understanding of lambda, not anything to do with wxPython.

even more, it was your understanding of argument passing :wink:

So, now the question is: how can I learn more about lambda?

googling will help, but don't focus on lambda per se, it's really not that special, but it does require you to understand name binding a bit more, particularly how key word arguments are handles.

lambda is just a special case of the more general notion of functions as real objects.

exactly!

lambda, callable class objects, and generators.

well, lambda isn't really different, the only difference is that a lambda function doesn't have to be given a name. For example, from your code:

# The lambda method
for i in range(3):
     self.button = wx.Button(self.panel, label="Button"+str(i),
                             pos=(100, 15 + 20*i ))
     self.Bind(wx.EVT_BUTTON,
               lambda evt, index=i: self.OnSetRank(evt,
                                                   index), self.button)

# use "def" in stead:

for i in range(3):
     self.button = wx.Button(self.panel, label="Button"+str(i),
                             pos=(100, 15 + 20*i ))
     def f(evt, index=i):
         return self.OnSetRank(evt, index)
     self.Bind(wx.EVT_BUTTON, f, self.button)

by the way, that can be written:
     self.button.Bind(wx.EVT_BUTTON, f)

or even:

for i in range(3):
     self.button = wx.Button(self.panel, label="Button"+str(i),
                             pos=(100, 15 + 20*i ))
     f = lambda evt, index=i: self.OnSetRank(evt, index)
     self.button.Bind(wx.EVT_BUTTON, f)

so "def" and "lambda" both create a function object -- lambda is just a little more convenient for quick in-line use like this.

So far, my working theory is that the only state the function contains before it begins executing is the default arguments, which are evaluated when the function is compiled.

I think that's right.

And the non-argument externals referenced within the function are resolved into 'references' not values, at compile time.

no -- they don't get a reference until run time...

But Python still has several concepts that elude me, and I don't know where to see the detailed descriptions,

Have you looked at the "Language Reference"?

nor do I seem to have tools that let me examine what's really happening.

well, you can look at the bytecode generated...

My self-assignment for this afternoon: "Programming Python" by Mark Lutz, 3rd edition, starting with pag 390 ('Passing in values with default arguments', 'Passing in values with enclosing scope references',

good idea -- also read anything you can find by Alex Martelli (and Tim Peters if you want to know about numerics..)

...) Although I've been through it before, maybe this time it'll begin making sense.

I think you need a real use-case before you "get" something.

By the way, this is one of the few things in python that is tricky in this way.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Christopher Barker wrote:

so "def" and "lambda" both create a function object --

Another way to look at it is that lambda creates an unnamed function that is only a single expression (the function body can't have statements in a lambda.) So anytime you can do something like this:

   def f(arg):
       return expr

then you can also write it as:

   f = lambda arg: expr

And if you don't need to assign the function object to a name, as in the other examples in this thread, then even the "f = " assignment above is superfluous.

···

lambda is just a little more convenient for quick in-line use like this.

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!