Python callbacks with arguments

Python Callback Function

Before implementing Callback Function in Python, first we will brush our understanding about what a Callback Function is.

A callback is a function that is passed as an argument to other function. This other function is expected to call this callback function in its definition. The point at which other function calls our callback function depends on the requirement and nature of other function.

Callback Functions are generally used with asynchronous functions.

Example for Callback Function: Callback Function can be passed to a function to print out the size of file after the function reads given text file.

Examples

1. A simple example for a Callback function

In this example, we will define a function named printFileLength() that takes file path and callback functions as arguments.

printFileLength() reads the file, gets the length of the file and at the end makes a call to the callback function.

Python Program

def callbackFunc(s): print('Length of the text file is : ', s) def printFileLength(path, callback): f = open(path, "r") length = len(f.read()) f.close() callback(length) if __name__ == '__main__': printFileLength("sample.txt", callbackFunc)
Length of the text file is : 56

You may pass different callback function as required. In the following program, we will define two functions callbackFunc1() and callbackFunc2() which we will use as callback functions for printFileLength(). But, we do not change the definition of printFileLength() function.

Читайте также:  javascript change image onclick event

Python Program

def callbackFunc1(s): print('Callback Function 1: Length of the text file is : ', s) def callbackFunc2(s): print('Callback Function 2: Length of the text file is : ', s) def printFileLength(path, callback): f = open(path, "r") length = len(f.read()) f.close() callback(length) if __name__ == '__main__': printFileLength("sample.txt", callbackFunc1) printFileLength("sample.txt", callbackFunc2)
Callback Function 1: Length of the text file is : 56 Callback Function 2: Length of the text file is : 56

Summary

In this tutorial of Python Examples, we learned what a Callback Function is, and how to implement a Callback Function in Python, with examples.

Источник

Passing Arguments to Callbacks

wxPyWiki

When binding events to callback, wxPython expects the call back to be a function that takes a single argument: the event object. There are often times when one might want to pass additional information into a callback function. A common use is when you have a bunch of widgets that all behave similarly, so you don’t want to write a different callback function for each one. One way to handle that is to have them all bound to the same callback, and then in the callback, figure out which widget the event came from by using Event.GetEventObject() or Event.GetId().

I find it more elegant to pass data directly into the callback, using the «lambda trick». lambda allows you to create a simple function in place in your code. So you can create a function that wraps the callback, passing some extra info in with keyword arguments. See the example below for a working application.

btn.Bind(wx.EVT_BUTTON, lambda evt, temp=button_name: self.OnButton(evt, temp) )

Bind() takes two (or more) arguments:

the event type and the callback.

The callback should be a python callable that takes one argument — the event object. In the usual case, that’s easy, something like:

 1  def OnButton(self, event):  2  some_stuff 

the self is the class instance object, so the event gets passed through as the only argument.

In this case, we are trying to pass some extra info into the callback: button_name. so we use a lamba:

lambda evt, temp=button_name:

creates a function that takes two arguments, but only the first (the event) is required, and the other has a default value. The way python keyword bindings work is that «temp» is bound to the OBJECT that is bound to button_name When the function is created — that’s key, ’cause this is in a loop, and that name is bound to a different object each time through the loop, and a new function object is created each time, each with a different object bound to «temp».

what the lambda function returns is return value of self.OnButton(evt, temp), with temp set to the button_name object.

so, the callback mechanism gets a callable that takes an event as an argument, and the OnButton method gets called with that event, and one other argument.

This is a simple case that could be handled in other ways, but remember that the extra data that is passed in can be any python object, indeed, more than one if you want.

Note that there is nothing special about lambda here — it just lets you cram it all onto one line. You could do:

 1  def callback(evt, temp=button_name):  2  return self.Onbutton(evt, temp)  3    4  btn.Bind(wx.EVT_BUTTON, callback ) 

and it would mean exactly the same thing.

Example

 1  #!/usr/bin/env python  2    3  import wx  4    5  class DemoFrame(wx.Frame):  6  """ This window displays a set of buttons """  7  def __init__(self, *args, **kwargs):  8  wx.Frame.__init__(self, *args, **kwargs)  9    10  sizer = wx.BoxSizer(wx.VERTICAL)  11  for button_name in ["first", "second", "third"]:  12  btn = wx.Button(self, label=button_name)  13  btn.Bind(wx.EVT_BUTTON, lambda evt, temp=button_name: self.OnButton(evt, temp) )  14  sizer.Add(btn, 0, wx.ALL, 10)  15    16  self.SetSizerAndFit(sizer)  17    18  def OnButton(self, Event, button_label):  19  print "In OnButton:", button_label  20    21    22  app = wx.App(False)  23  frame = DemoFrame(None, title="Lambda Bind Test")  24  frame.Show()  25  app.MainLoop() 

Example 2 — Inline functions, no lambdas

 1  import wx  2    3  class DemoFrame(wx.Frame):  4  """ This window displays a set of buttons """  5  def __init__(self, *args, **kwargs):  6  wx.Frame.__init__(self, *args, **kwargs)  7    8  sizer = wx.BoxSizer(wx.VERTICAL)  9  for button_name in ["first", "second", "third"]:  10  btn = wx.Button(self, label=button_name)  11    12  def OnButton(event, button_label=button_name):  13  print "In OnButton:", button_label  14    15  btn.Bind(wx.EVT_BUTTON, OnButton)  16  sizer.Add(btn, 0, wx.ALL, 10)  17  self.SetSizerAndFit(sizer)  18    19    20  app = wx.App(False)  21  frame = DemoFrame(None, title="Lambda Bind Test")  22  frame.Show()  23  app.MainLoop() 

Alternative way using functools

If you are on Python 2.5 or higher, you can also make use of the functools package instead of using lambda for this. Here’s the example from above written using functools.partial:

 1  #!/usr/bin/env python  2    3  from functools import partial  4  import wx  5    6  class DemoFrame(wx.Frame):  7  """ This window displays a set of buttons """  8  def __init__(self, *args, **kwargs):  9  wx.Frame.__init__(self, *args, **kwargs)  10    11  sizer = wx.BoxSizer(wx.VERTICAL)  12  for button_name in ["first", "second", "third"]:  13  btn = wx.Button(self, label=button_name)  14  btn.Bind(wx.EVT_BUTTON, partial( self.OnButton, button_label = button_name ) )  15  sizer.Add(btn, 0, wx.ALL, 10)  16    17  self.SetSizerAndFit(sizer)  18    19  def OnButton(self, Event, button_label):  20  print "In OnButton:", button_label  21    22    23  app = wx.App(False)  24  frame = DemoFrame(None, title="functools.partial Bind Test")  25  frame.Show()  26  app.MainLoop() 

For more information on functools.partial see also http://docs.python.org/library/functools.html .

Passing Arguments to Callbacks (последним исправлял пользователь c-98-246-90-205 2011-07-29 18:48:24)

Источник

Passing Arguments to Callbacks

wxPyWiki

When binding events to callback, wxPython expects the call back to be a function that takes a single argument: the event object. There are often times when one might want to pass additional information into a callback function. A common use is when you have a bunch of widgets that all behave similarly, so you don’t want to write a different callback function for each one. One way to handle that is to have them all bound to the same callback, and then in the callback, figure out which widget the event came from by using Event.GetEventObject() or Event.GetId().

I find it more elegant to pass data directly into the callback, using the «lambda trick». lambda allows you to create a simple function in place in your code. So you can create a function that wraps the callback, passing some extra info in with keyword arguments. See the example below for a working application.

btn.Bind(wx.EVT_BUTTON, lambda evt, temp=button_name: self.OnButton(evt, temp) )

Bind() takes two (or more) arguments:

the event type and the callback.

The callback should be a python callable that takes one argument — the event object. In the usual case, that’s easy, something like:

 1  def OnButton(self, event):  2  some_stuff 

the self is the class instance object, so the event gets passed through as the only argument.

In this case, we are trying to pass some extra info into the callback: button_name. so we use a lamba:

lambda evt, temp=button_name:

creates a function that takes two arguments, but only the first (the event) is required, and the other has a default value. The way python keyword bindings work is that «temp» is bound to the OBJECT that is bound to button_name When the function is created — that’s key, ’cause this is in a loop, and that name is bound to a different object each time through the loop, and a new function object is created each time, each with a different object bound to «temp».

what the lambda function returns is return value of self.OnButton(evt, temp), with temp set to the button_name object.

so, the callback mechanism gets a callable that takes an event as an argument, and the OnButton method gets called with that event, and one other argument.

This is a simple case that could be handled in other ways, but remember that the extra data that is passed in can be any python object, indeed, more than one if you want.

Note that there is nothing special about lambda here — it just lets you cram it all onto one line. You could do:

 1  def callback(evt, temp=button_name):  2  return self.Onbutton(evt, temp)  3    4  btn.Bind(wx.EVT_BUTTON, callback ) 

and it would mean exactly the same thing.

Example

 1  #!/usr/bin/env python  2    3  import wx  4    5  class DemoFrame(wx.Frame):  6  """ This window displays a set of buttons """  7  def __init__(self, *args, **kwargs):  8  wx.Frame.__init__(self, *args, **kwargs)  9    10  sizer = wx.BoxSizer(wx.VERTICAL)  11  for button_name in ["first", "second", "third"]:  12  btn = wx.Button(self, label=button_name)  13  btn.Bind(wx.EVT_BUTTON, lambda evt, temp=button_name: self.OnButton(evt, temp) )  14  sizer.Add(btn, 0, wx.ALL, 10)  15    16  self.SetSizerAndFit(sizer)  17    18  def OnButton(self, Event, button_label):  19  print "In OnButton:", button_label  20    21    22  app = wx.App(False)  23  frame = DemoFrame(None, title="Lambda Bind Test")  24  frame.Show()  25  app.MainLoop() 

Example 2 — Inline functions, no lambdas

 1  import wx  2    3  class DemoFrame(wx.Frame):  4  """ This window displays a set of buttons """  5  def __init__(self, *args, **kwargs):  6  wx.Frame.__init__(self, *args, **kwargs)  7    8  sizer = wx.BoxSizer(wx.VERTICAL)  9  for button_name in ["first", "second", "third"]:  10  btn = wx.Button(self, label=button_name)  11    12  def OnButton(event, button_label=button_name):  13  print "In OnButton:", button_label  14    15  btn.Bind(wx.EVT_BUTTON, OnButton)  16  sizer.Add(btn, 0, wx.ALL, 10)  17  self.SetSizerAndFit(sizer)  18    19    20  app = wx.App(False)  21  frame = DemoFrame(None, title="Lambda Bind Test")  22  frame.Show()  23  app.MainLoop() 

Alternative way using functools

If you are on Python 2.5 or higher, you can also make use of the functools package instead of using lambda for this. Here’s the example from above written using functools.partial:

 1  #!/usr/bin/env python  2    3  from functools import partial  4  import wx  5    6  class DemoFrame(wx.Frame):  7  """ This window displays a set of buttons """  8  def __init__(self, *args, **kwargs):  9  wx.Frame.__init__(self, *args, **kwargs)  10    11  sizer = wx.BoxSizer(wx.VERTICAL)  12  for button_name in ["first", "second", "third"]:  13  btn = wx.Button(self, label=button_name)  14  btn.Bind(wx.EVT_BUTTON, partial( self.OnButton, button_label = button_name ) )  15  sizer.Add(btn, 0, wx.ALL, 10)  16    17  self.SetSizerAndFit(sizer)  18    19  def OnButton(self, Event, button_label):  20  print "In OnButton:", button_label  21    22    23  app = wx.App(False)  24  frame = DemoFrame(None, title="functools.partial Bind Test")  25  frame.Show()  26  app.MainLoop() 

For more information on functools.partial see also http://docs.python.org/library/functools.html .

Passing Arguments to Callbacks (последним исправлял пользователь c-98-246-90-205 2011-07-29 18:48:24)

Источник

Оцените статью