jhub1 jhub1 - 2 months ago 7
Python Question

Looping through list of functions in a function in Python dynamically

I'm a beginner and I can't even find other questions that are similar so I'm wondering if I'm using the wrong search terms. So I'd like to see if it's possible to run through a list of functions in a function.

This is the closest thing I could find but it is looping through an entire module. I only want to use a pre-selected list of functions.



Python documentation



Rules for this code:


  1. Given a string, check each letter to see if any of the 5 tests fulfill.

  2. If a minimum of 1 letter passes a check, return True.

  3. If all letters in the string fails the check, return False.

  4. For each letter in the string, we will check these functions: isalnum(), isalpha(), isdigit(), islower(), isupper()

  5. The result of each test should print to different lines.



Sample Input

qA2


Sample Output (must print to separate lines, True if at least one letter passes, or false is all letters fail each test):

True
True
True
True
True


I wrote this for one test. Of course I could just write 5 different sets of code but that seems ugly. Then I started wondering if I could just loop through all the tests they're asking for.

Code for just one test:

raw = 'asdfaa3fa'
counter = 0
for i in xrange(len(raw)):
if raw[i].isdigit() == True: ## This line is where I'd loop in diff func's
counter = 1
print True
break
if counter == 0:
print False


My fail attempt to run a loop with all the tests:

raw = 'asdfaa3fa'
lst = [raw[i].isalnum(),raw[i].isalpha(),raw[i].isdigit(),raw[i].islower(),raw[i].isupper()]
counter = 0
for f in range(0,5):
for i in xrange(len(raw)):
if lst[f] == True: ## loop through f, which then loops through i
print lst[f]
counter = 1
print True
break
if counter == 0:
print False



  1. So in conclusion - How I fix this code to fulfill all the rules up there?

  2. Bonus question - Is there anyway to improve my code (more Pythonic,
    efficient, etc.)?






Using info from all the comments - this code fulfills the rules stated above, looping through each method dynamically as well.

raw = 'ABC'
functions = [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper]

for func in functions:
print any(func(letter) for letter in raw)


getattr approach (I think this is called introspection method?)

raw = 'ABC'

meths = ['isalnum', 'isalpha', 'isdigit', 'islower', 'isupper']
for m in meths:
print any(getattr(c,m)() for c in raw)


List comprehension approach:

from __future__ import print_function ## Changing to Python 3 to use print in list comp

raw = 'ABC'
functions = [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper]
solution = [print(func(raw)) for func in functions]

Answer

The way you are looping through a list of functions is slightly off. This would be a valid way to do it. The functions you need to store in the list are the generic string functions given by str.funcname. Once you have those list of functions, you can loop through them using a for loop, and just treat it like a normal function!

raw = 'asdfaa3fa'
functions = [str.isalnum, str.isalpha, str.isdigit, str.islower,  str.isupper]  # list of functions

for fn in functions:     # iterate over list of functions, where the current function in the list is referred to as fn
    for ch in raw:       # for each character in the string raw
        if fn(ch):        
            print(True)
            break

Sample outputs:

Input                     Output
===================================
"qA2"         ----->      True True True True True
"asdfaa3fa"   ----->      True True True True

Also I notice you seem to use indexing for iteration which makes me feel like you might be coming from a language like C/C++. The for in loop construct is really powerful in python so I would read up on it (y).

Above is a more pythonic way to do this but just as a learning tool, I wrote a working version that matches how you tried to do it as much as possible to show you where you went wrong specifically. Here it is with comments:

raw = 'asdfaa3fa'
lst = [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper]   # notice youre treating the functions just like variables and aren't actually calling them. That is, you're writing str.isalpha instead of str.isalpha()
for f in range(0,5):
    counter = 0
    for i in xrange(len(raw)):
        if lst[f](raw[i]) == True:  # In your attempt, you were checking if lst[f]==True; lst[f] is a function so you are checking if a function == True. Instead, you need to pass an argument to lst[f](), in this case the ith character of raw, and check whether what that function evaluates to is true
            print lst[f] 
            counter = 1
            print True
            break
    if counter == 0:
        print False