11

I'm looking for a better way to call functions based on a variable in Python vs using if/else statements like below. Each status code has a corresponding function

if status == 'CONNECT':
 return connect(*args, **kwargs)
elif status == 'RAWFEED':
 return rawfeed(*args, **kwargs)
elif status == 'RAWCONFIG':
 return rawconfig(*args, **kwargs)
elif status == 'TESTFEED':
 return testfeed(*args, **kwargs)
...

I assume this will require some sort of factory function but unsure as to the syntax

asked Mar 25, 2009 at 10:04

8 Answers 8

38

you might find getattr useful, I guess

import module
getattr(module, status.lower())(*args, **kwargs)
answered Mar 25, 2009 at 10:08
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for this example, I didn't realize getattr() also worked on modules
20

The canonical way to do this is to use a dictionary to emulate switch or if/elif. You will find several questions to similar problems here on SO.

Put your functions into a dictionary with your status codes as keys:

funcs = {
 'CONNECT': connect,
 'RAWFEED': rawfeed,
 'RAWCONFIG' : rawconfig,
 'TESTFEED': testfeed
}
funcs[status](*args, **kwargs)
answered Mar 25, 2009 at 10:13

7 Comments

funcs['status'] will raise KeyError
I think it is a safe way, it raises an exception when status is an unexpected method name.
DRY rarely applies in cases like this. The initial list of functions may have string-like names; but this often diverges into more complex relationships.
@S.Lott: the question title states 'dynamic functions names'. This is static mapping.
This is not the canonical pythonic way for function dispatching. getattr is the canonical method in this case
|
15

assuming that these functions belong to some module:

import module
return getattr(module, status.lower()).__call__(*args, **kwargs)
answered Mar 25, 2009 at 10:10

Comments

6

it seams that you can use getattr in a slightly different (in my opinion more elegant way)

import math
getattr(math, 'sin')(1)

or if function is imported like below

from math import sin

sin is now in namespace so you can call it by

vars()['sin'](1)
answered Mar 25, 2009 at 10:18

Comments

4

Some improvement to SilentGhost's answer:

globals()[status.lower()](*args, **kwargs)

if you want to call the function defined in the current module.

Though it looks ugly. I'd use the solution with dictionary.

answered Mar 25, 2009 at 10:33

Comments

3
answered Mar 25, 2009 at 10:19

1 Comment

Link is dead, decrementing score. Sorry for that.
1

I encountered the same problem previously. Have a look at this question, I think its what you are looking for.

Dictionary or If Statements

Hope this is helpful

Eef

answered Mar 25, 2009 at 10:27

Comments

0

some change from previous one:

funcs = {
'CONNECT': connect,
'RAWFEED': rawfeed,
'RAWCONFIG' : rawconfig,
'TESTFEED': testfeed
}
func = funcs.get('status')
if func:
 func(*args, **kwargs)
answered Mar 25, 2009 at 10:16

2 Comments

no it doesn't. it's the same error that heikogerlach had in the beginning.
I replaced 'status' with the variable, so I suppose technically it doesn't. I'm more interested in the method than semantics

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.