ottodidakt
ottodidakt

Reputation: 3741

What is the idiomatic way of invoking a list of functions in Python?

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

Answers (4)

PaulMcG
PaulMcG

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

przemo_li
przemo_li

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

Stephan202
Stephan202

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

quamrana
quamrana

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

Related Questions