2

I currently have two Python 3 scripts: chooseFunc.py and testFuncs.py.

My goal is to write a function chooseFunction in the former script, then import the function for usage within the latter script. Upon execution of chooseFunction() in testFuncs.py, it should display the functions present in testFuncs.py and allow the user to choose which func() to run. Thefuncs have no args for the purpose at hand.

I've created a function chooseFunction as such:

def chooseFunction(module):
    funcList = []

    for key, value in module.__dict__.items():
        if callable(value) and value.__name__ !='<lambda>' and  value.__name__ !='chooseFunction':
            funcList.append(value)

    for funcIdx, myFunc in enumerate(funcList):
        print(funcIdx, myFunc.__name__ )

    chosenIdx = int(input('Choose function... ·\n'))

    return funcList[chosenIdx]()

Currently, when executed in testFuncs.py as follows:

from chooseFunc import chooseFunction
import sys

def func1():
    print('func1')

def func2():
    print('func2')

chooseFunction(module=sys.modules[__name__])

the argument module=sys.modules[__name__] on the last row has to be provided.

How do I change this behavior such that chooseFunction retrieves the list of functions present in testFuncs.py, without having to provide the module argument above?

Apologies in advance for any potential inconsistencies, this is my first entry on Stack Exchange... General feedback is appreciated!

1 Answers1

2

Not quite to the specification you need (i.e. this is just a 1-file solution):

You can use globals() to get the global symbol table and make an iterable that lists all the callable() functions

As a dictionary:

funcs = {k:v for k, v in list(globals().items()) if callable(v)}

Or as a list:

funcs = [v for _,v in list(globals().items()) if callable(v)]

Example Useage:

# functions.py

def func1(msg):
    print("This is func 1: " + msg)

def func2(msg):
    print("This is func 2: " + msg)

def func3(msg):
    print("This is func 3: " + msg)

if __name__ == '__main__':

    funcs = [v for _,v in list(globals().items()) if callable(v)]

    # Prompt user for choice
    print("Choose function to run:")
    for i, f in enumerate(funcs):
        print('\t[{:d}] {:s}'.format(i+1, f.__name__))
    user_choice = int(input('\n>>> ')) - 1

    # Run the function
    funcs[user_choice]('hello there')

Terminal output:

$ python functions.py
Choose function to run:
    [1] func1
    [2] func2
    [3] func3

>>> 2
This is func 2: hello there
Jamie Phan
  • 1,112
  • 7
  • 15
  • Thank you Jamie. Although it doesn't fully answer my question (my code also successfully runs "chooseFunction" if called within same script, with dummy "testFuncs" present of course), your answer is still insightful to a Python newbie like me. This is much more readable :) – Jakob Nilsson Apr 17 '20 at 18:21