1

I have a number of functions called func_1, func_2, ... I'd like to call each of them in a for loop.

I could do:

for f in [func_1, func_2, func_3]:
    print f('foo', 'bar')

but I'd like less typing. Is there any way to generate the names, something like:

for f in ['func_%s' % range(1,5)]:
    print f('foo', 'bar')

This fails with 'str' object is not callable, but is there anything like this that works?

EDIT: I'm testing a number of alternative versions of func. They are all supposed to give the same result, but with different implementations. I control the inputs and this is not in production.

However, this is bad and possibly dangerous practice in other contexts. See the comments and answers.

martineau
  • 119,623
  • 25
  • 170
  • 301
foosion
  • 7,619
  • 25
  • 65
  • 102
  • 5
    Yes, but this is **bad** design. Usually you should give functions an informative name, a *call-by-name* is usually dangerous. – Willem Van Onsem Jun 24 '17 at 14:04
  • 2
    This is the epitome of the [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). You shouldn't have to do this in the first place. – stelioslogothetis Jun 24 '17 at 14:05
  • 2
    Explicitness, readability, maintainability and testability are very important in software practice. This goes against each of those. – idjaw Jun 24 '17 at 14:06
  • @WillemVanOnsem in this context, the names are informative. func_2 is the second alternative version of func. See the edit, as this was not clear from the original question – foosion Jun 24 '17 at 14:11
  • @idjaw See the edit. This is for testing alternatives. Therefore, things such as maintainability are less important. I think of a new implementation, then bump `range`. The tests are not all that complex; if they were I'd be doing something more sophisticated. – foosion Jun 24 '17 at 14:14
  • This is unfortunately closed, so I'll post a hint instead of an answer. You could put the functions all in one module, and then do `import alternatives; funcs = [f for f in alternatives where f.__name__.startswith("func")]`. I haven't tested this, the syntax to iterate over a module's contents might be different. This is a bit like how test runners find unit tests. – jdm Jun 24 '17 at 14:52

2 Answers2

3

You could look them up in the local scope:

for f in ['func_%s' % range(1,5)]:
    print locals()[f]('foo', 'bar')

The locals() function returns a dictionary of names to values in the local scope. If they are global functions, use globals().

Artyer
  • 31,034
  • 3
  • 47
  • 75
1

You can use eval. However it is very dangerous to use eval. Be careful while playing with it.

for f in ['func_%s' % range(1,5)]:
    print eval(f)('foo', 'bar')
Jay Parikh
  • 2,419
  • 17
  • 13
  • 4
    Leaving [this](https://stackoverflow.com/questions/1832940/is-using-eval-in-python-a-bad-practice) here because friends don't let friends eval. – idjaw Jun 24 '17 at 14:04
  • @idjaw that's why my comments are there. please read it carefully. Hope u have read it. – Jay Parikh Jun 24 '17 at 14:05
  • Yes, I did read it. Otherwise I would not have left a comment about it. Did you read my link I left? :) – idjaw Jun 24 '17 at 14:07
  • @idjaw so why negative rating for this. – Jay Parikh Jun 24 '17 at 14:08
  • I did not downvote you. – idjaw Jun 24 '17 at 14:08
  • @idjaw no problem. Thanks :) – Jay Parikh Jun 24 '17 at 14:09
  • @idjaw In my context (see question edit), `eval` is not dangerous. I know the inputs and it's not in production. Am I missing something? – foosion Jun 24 '17 at 14:16
  • 1
    @foosion You can do whatever you want. But please keep in mind that these answers help the community as a whole as well. And by accepting answers that are clearly using very bad software practice, it also indicates to other readers that "hey, I can do this too" who don't know better. Keep that in mind too. But, yeah...you can do whatever you want here. :) But, it's also important to indicate to the readers the dangers here too, which is also why I put the link in the comment to help people understand what eval is. – idjaw Jun 24 '17 at 14:24
  • 3
    If you're going to use `eval`, at least use it right - human errors are another reason why using `eval` can go horribly wrong. The current code doesn't work. – Aran-Fey Jun 24 '17 at 14:28
  • @Rawing Good point. I never use `eval`, for the reasons given here, so I didn't even realize the posted code is wrong. – foosion Jun 24 '17 at 14:36
  • guys, i have not tried in my code editor. its about brackets misplacing. editiing now. it will work now. – Jay Parikh Jun 24 '17 at 14:38