Reputation: 3741
I have a list of callback functions that I need to invoke when an event is fired. Is this idiomatic python?
def first_callback(m):
print 'first ' + m
def second_callback(m):
print 'second ' + m
lst = [first_callback, second_callback]
map(lambda x: x("event_info"),lst) #is this how you do it?
Upvotes: 4
Views: 620
Reputation: 63709
I have to ask if this is truly the OP's intent. When I hear "invoke a list of functions", I assume that just looping over the list of functions and calling each one is so obvious, that there must be more to the question. For instance, given these two string manipulators:
def reverse(s):
return s[::-1]
import random
def randomcase(s):
return ''.join(random.choice((str.upper, str.lower))(c) for c in s)
manips = [reverse, randomcase]
s = "Now is the time for all good men to come to."
# boring loop through list of manips
for fn in manips:
print fn(s)
# more interesting chain through list of manips
s_out = s
for fn in manips:
s_out = fn(s_out)
print s_out
The first loop prints:
.ot emoc ot nem doog lla rof emit eht si woN
NOW IS THe tIMe for aLL good meN TO COme To.
The second chains the output of the first function to the input of the next, printing:
.oT EMoC OT NeM DOog lla RoF emit EHt SI won
This second method allows you to compose more complex functions out of several simple ones.
Upvotes: 0
Reputation: 350
If you have dynamically created list of functions simple for is good:
for function in list_of_functions: function(your_argument_here)
But if you use OOP and some classes should know that some event happens (generally changes) consider introducing Observer design pattern: http://en.wikipedia.org/wiki/Observer_pattern,
Introducing pattern means refactoring working code to that pattern (and stopping when code look good even if not whole patter was introduced) read more in "Refactoring to patterns" Kerievsky.
Upvotes: 0
Reputation: 61499
Use map
only for functions without side effects (like print
). That is, use it only for functions that just return something. In this case a regular loop is more idiomatic:
for f in lst:
f("event_info")
Edit: also, as of Python 3.0, map
returns an iterator instead of a list. Hence in Python 3.0 the code given in the question will not call any function, unless all elements in the generator are evaluated explicitly (e.g. by encapsulating the call to map
inside list
). Luckily the 2to3 tool will warn about this:
File map.py
:
map(lambda x: x, range(10))
2to3-3.0 map.py
output:
RefactoringTool: Skipping implicit fixer: buffer
RefactoringTool: Skipping implicit fixer: idioms
RefactoringTool: Skipping implicit fixer: set_literal
RefactoringTool: Skipping implicit fixer: ws_comma
--- map.py (original)
+++ map.py (refactored)
@@ -1,1 +1,1 @@
-map(lambda x: x, range(10))
+list(map(lambda x: x, list(range(10))))
RefactoringTool: Files that need to be modified:
RefactoringTool: map.py
RefactoringTool: Warnings/messages while refactoring:
RefactoringTool: ### In file map.py ###
RefactoringTool: Line 1: You should use a for loop here
Upvotes: 18
Reputation: 39354
You could also write a list comprehension:
[f("event_info") for f in lst]
However, it does have the side-effect of returning a list of results.
Upvotes: 3