1

There are many questions similar to this out there but none of the answers solved my issue.

I have defined several functions that parse large data sets. First I call the data, then I organize the data (represented as rows and columns in a .txt) into lists which I will index for individual data entries. After that I establish my functions that will work through the lists one at a time. The code looks like:

f = open(fn)
for line in iter(f):

    entries = [i for i in line.split() if i]

    def function_one():
        if entries[0] == 150:
            # do something
    def function_two():
        if entries[1] == 120:
        # do something else
    def function_three():
        if len(entries) > 10:
        # do something else

etc. etc.

I have attempted to prompt the user asking what function they would like to execute as each function returns different things about the data set. My attempt is as follows:

    f_call = input('Enter Function Name: ')
    if f_call in locals().keys() and callable(locals()['f_call']):
        locals()['f_call']()
    else:
        print('Function Does Not Exist')

When I run the script, I am prompted to 'Enter Function Name:' and if I type in 'function_one' and return, it prints 'Function Does Not Exist'. I want to see that, if entered correctly, the script will execute only the function that the user entered. If the user input is correct, the function should run and print the parsed data.

I have also attempted using a dict to store the functions but I have not had success.

Any help would be greatly appreciated.

DRauch
  • 57
  • 1
  • 7
  • Possible duplicate of [How do I use user input to invoke a function in Python?](https://stackoverflow.com/questions/16625454/how-do-i-use-user-input-to-invoke-a-function-in-python) – midori Jul 10 '17 at 16:49
  • remove the "" in `if f_call in locals().keys() and callable(locals()['f_call'])` – PRMoureu Jul 10 '17 at 16:49
  • @tinySandy As indicated, I was unsuccessful in applying the dictionary solutions presented in the suggested duplicate. – DRauch Jul 10 '17 at 17:23
  • Why in the world are you (re)defining your functions in a loop? Let's start with that one... – zwer Jul 10 '17 at 18:21
  • @zwer My understanding was that in order to work through the data set line by line (15000+ lines, variable column lengths), a for iter would have to be used to analyze all lines individually. If that's not the case, I am totally open to other suggestions. I am brand new to Python and coding as a whole. – DRauch Jul 10 '17 at 18:40
  • @DRauch - it's not about reading the file, it's about you re-defining the functions in each loop. Create your functions outside of the loop and pass them the current item in the loop instead (e.g. define a function like `def function_one(param): ...` and then just call it in your loop, when needed, as `function_one(entries)` (or another dynamically allocated name, but we'll get to that...) – zwer Jul 10 '17 at 18:51
  • @zwer Okay. I am understanding most of what you are saying. Perhaps I need a refresher of passing items into functions. Are you suggesting that I can move the functions out of the for loop and then put the user input for selecting a function inside the for loop? – DRauch Jul 10 '17 at 19:01

3 Answers3

1

to make your code work, just keep the variable f_call without '' when you call it

f_call = input('Enter Function Name: ')
if f_call in locals().keys() and callable(locals()[f_call]):
    locals()[f_call]()
else:
    print('Function Does Not Exist')
PRMoureu
  • 12,817
  • 6
  • 38
  • 48
1

Based on your comments, I think you're trying to achieve something like this:

def function_one(data):
    if data[0] == 150:
        pass  # do something

def function_two(data):
    if data[1] == 120:
        pass  # do something else

def function_three(data):
    if len(data) > 10:
        pass # do something entirely different

This defines your functions that accept arguments so you can re-use them later on. Then you'd like to ask the user which function to use when processing the data, so:

while True:  # loop while we don't get a valid input
    user_function = input('Enter a function name to use: ')  # ask the user for input
    if user_function in locals() and callable(locals()[user_function]):  # if it exists...
        user_function = locals()[user_function]  # store a pointer to the function
        break  # break out of the while loop since we have our valid input
    else:
        print('Invalid function name, try again...')

Finally, you can load your file, read it line by line, split it up and process it by the function decided by the user:

with open(file_name, "r") as f:
    for line in f:
        entries = line.split()  # no need to check for empty elements
        user_function(entries)  # call the user selected function and pass `entries` to it

Of course, you can do further processing afterwards.

UPDATE - Here's a simple test for the above code, given the file test_file.txt containing:

tokenized line 1
tokenized line 2
tokenized line 3

and file_name = "test_file.txt" defined in the file, while the functions are defined as:

def function_one(data):
    print("function_one called: {}".format(data))

def function_two(data):
    print("function_two called: {}".format(data))

def function_three(data):
    print("function_three called: {}".format(data))

If you execute the code this is the output/trace:

Enter a function name to use: bad_name_on_purpose
Invalid function name, try again...
Enter a function name to use: function_two
function_two called: ['tokenized', 'line', '1']
function_two called: ['tokenized', 'line', '2']
function_two called: ['tokenized', 'line', '3']
zwer
  • 24,943
  • 3
  • 48
  • 66
  • Logically, this makes much more sense to me. I have updated my code to your suggestion but when running the code, nothing prints. My description may have been misleading in that it did not specify that I want the data parsing to print after each line (assuming conditions are met), though this is something I am doing within the functions so I am not sure why it won't work. I feel as if I am doing something incorrect with the arguments placed in the functions. – DRauch Jul 10 '17 at 21:03
  • @DRauch - I've added some test code above that demonstrates how it all works. Compare it with your setup and see if you're missing some component. If you're trying to compare individual values, keep in mind that `str.split()` returns a list of strings so if you want to compare them with integers you have to convert them to integers first (i.e. `if int(data[0]) == 150...`) – zwer Jul 10 '17 at 21:29
  • The error shown in my IDE is "shadows name 'column' from outer scope". I think the way my original for loop was altered has changed how the data is being stored. My full code had some of `entries` stored as a new list `column` for simplicity. So I tried using `column` as the argument for all the functions but I am still getting nothing when I run the script. I feel as though my issue is much greater than the one posed in the question above. – DRauch Jul 10 '17 at 21:59
0

It may not be the most efficient way to fix it, but you could use something like this:

f_call = raw_input('Enter Function Name: ')
if f_call == "function_one":
    function_one()
if f_call == "function_two":
    function_two()
if f_call == "function_three":
    function_three()
else:
    print('Function Does Not Exist')
Paul
  • 88
  • 9
  • I tried that as well. When running the script, the user is prompted to `'Enter Function Name:'` repeatedly, rather than actually running the function that has been entered. – DRauch Jul 10 '17 at 17:28
  • That may be because you put it inside of the loop. You will want to put my script after the functions are created and not in the loop. – Paul Jul 10 '17 at 17:30
  • Correct, but if I move it out of the loop, nothing happens when I enter a function name. – DRauch Jul 10 '17 at 17:33
  • Maybe define the functions outside of the loop first – Paul Jul 10 '17 at 17:42
  • I have used the for loop as a means of working through each line individually one by one so that the selected function will analyze one line, then the next, and so on... I was led to believe this is the proper way of iterating through each line. If that's incorrect, please let me know. I am still a beginner programmer so any advice is greatly appreciated. – DRauch Jul 10 '17 at 18:42