在python中动态循环遍历函数列表

Looping through list of functions in a function in Python dynamically

我想看看是否可以运行一个函数中的函数列表。我能找到的最接近的东西就是在整个模块中循环。我只想使用预先选择的函数列表。

这是我最初的问题:

  • 给定一个字符串,检查每个字母,看看5个测试中是否有一个完成。
  • 如果至少有1个字母通过支票,则返回"真"。
  • 如果字符串中的所有字母都未通过检查,则返回false。
  • 对于字符串中的每个字母,我们将检查以下函数:isalnum()、isalpha()、isdigit()、islower()、isupper()。
  • 每个测试的结果应打印到不同的行。
  • 样本输入

    1
        qA2

    样本输出(必须打印到单独的行,如果至少有一个字母通过,则为真;如果所有字母都未通过每次测试,则为假):

    1
    2
    3
    4
    5
        True
        True
        True
        True
        True

    我写这个是为了一个测试。当然,我可以只写5组不同的代码,但这看起来很难看。然后我开始想我是否可以循环通过他们要求的所有测试。

    仅用于一个测试的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
        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

    我尝试用所有测试运行一个循环失败:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
        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
    2
    3
    4
    5
        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方法(我认为这称为内省方法?)

    1
    2
    3
    4
    5
        raw = 'ABC'

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

    列表理解方法:

    1
    2
    3
    4
    5
        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]


    循环遍历函数列表的方式稍微有点偏离。这是一种有效的方法。需要存储在列表中的函数是str.funcname提供的通用字符串函数。一旦您拥有了这些函数列表,就可以使用for循环来循环它们,并将其视为普通函数!

    1
    2
    3
    4
    5
    6
    7
    8
    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

    样品输出:

    1
    2
    3
    4
    Input                     Output
    ===================================
    "qA2"         ----->      True True True True True
    "asdfaa3fa"   ----->      True True True True

    我还注意到,您似乎使用迭代的索引,这让我感觉您可能来自像C/C++这样的语言。for-in-loop构造在python中非常强大,所以我将阅读它(y)。

    上面是一个更Python式的方法,但作为一个学习工具,我写了一个工作版本,匹配你如何尽可能多地做,以显示你具体哪里出错了。这里有评论:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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

    好吧,所以第一个问题很简单。简单的方法就是

    1
    2
    3
    4
    5
    6
    def foo(raw):
      for c in raw:
        if c.isalpha(): return True
        if c.isdigit(): return True
        # the other cases
      return False

    千万不要忽视最简单的事情。

    现在,如果您想动态地进行这项工作——这是您可能需要的神奇关键字,那么您需要应用类似这样的内容(从另一个问题中摘录):

    1
    2
    3
    4
    meths = [isalnum, isalpha, isdigit, islower, isupper]
    for c in raw:    
      for m in meths:
        getattr(c, m)()

    警告,这是一个未经测试的代码,旨在为您提供这个想法。这里的关键概念是,对象的方法与其他任何方法一样都是属性,因此,例如,getattr("a","isalpha")()执行以下操作:

    • 使用getattr"a"的属性字典中搜索名为isalpha的方法。
    • 返回该方法本身--
    • 然后使用()调用该方法,后者是Python中的函数应用程序运算符。

    请参见此示例:

    1
    2
    In [11]: getattr('a', 'isalpha')()
    Out[11]: True


    我猜你是在验证密码的复杂性,我还想说的是,接受输入并说"假"的软件,没有任何迹象表明用户有敌意,所以最重要的不是"如何循环使用嵌套的char函数代码向导(*)",而是"提供良好的反馈",并提出以下建议:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    raw = 'asdfaa3fa'

    import re

    def validate_password(password):
       """ This function takes a password string, and validates it
            against the complexity requirements from {wherever}
            and returns True if it's complex enough, otherwise False"""


        if not re.search('\d', password):
            print("Error: password needs to include at least one number")
            return False

        elif not re.search('[a-z]', password):
            print("Error: password must include at least one lowercase letter")
            return False

        elif not re.search('[A-Z]', password):
            print("Error: password must include at least one uppercase letter")
            return False

        print("Password is OK")
        return True

    validate_password(raw)

    在repl.it网上尝试

    regex搜索检查一次调用中字符和数字的范围,这比循环字符更整洁。

    (ps.您的函数重叠;一个字符串中的字符与'isupper'、'islower'和'isnumeric'匹配,它已经包含'isadigit'和'isalnum'。更有趣的是处理像!这样的字符,这些字符不是大写、小写、数字或alnum)。

    (*)与其他答案一样,函数巫术通常正是我要回答的问题,但是已经回答的问题太多了,我也可以用其他方式来回答:p


    所有其他答案都是正确的,但是由于您是初学者,我想在您的代码中指出问题:

    1
    lst = [raw[i].isalnum(),raw[i].isalpha(),raw[i].isdigit(),raw[i].islower(),raw[i].isupper()]

    首先:不确定我当前在您的代码中截取了哪个值,但它似乎指向了字符串中的某个位置——这会导致对单个字符进行评估,而不是对整个字符串进行原始处理。

    第二:当您构建列表时,您已经在调用要插入的方法,其效果不是它们自己插入的函数,而是它们的返回值(这就是为什么您在print语句中看到所有这些真正的值)。

    尝试如下更改代码:

    1
    lst = [raw.isalnum, raw.isalpha, raw.isdigit, raw.islower, raw.isupper]


    要回答原始问题:

    1
    2
    3
    4
    raw = 'asdfa3fa'
    functions = [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper]
    isanything = [func(raw) for func in functions]
    print repr(isanything)


    您可以使用内省来遍历对象的所有属性,无论它们是函数还是其他类型。

    然而,您可能不想在这里这样做,因为str有很多函数属性,您只对其中的五个感兴趣。最好还是照你的方式去做,把你想要的五个列出来。

    另外,如果不想循环使用字符串中的每个字符,也不需要循环;这些函数已经查看了整个字符串。


    由于您正在循环遍历简单项列表,并试图查找函数的all是否具有any有效结果,因此您可以简单地定义要调用输入并返回该结果的函数列表。下面是一个相当类似于Python的例子,说明你正在努力实现的目标:

    1
    2
    def checker(checks, value):
        return all(any(check(r) for r in value) for check in checks)

    测试出来:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> def checker(checks, value):
    ...     return all(any(check(r) for r in value) for check in checks)
    ...
    >>> checks = [str.isalnum, str.isalpha, str.isdigit, str.islower, str.isupper]
    >>> checker(checks, 'abcdef123ABC')
    True
    >>> checker(checks, 'abcdef123')
    False
    >>>

    请查看此一行解决方案以解决您的问题。这个问题来自hackrank。我使用内置的getattr函数遍历函数列表。

    1
    2
    s='qA2'
    [print(bool(list(filter(lambda x : getattr(x, func)(),s)))) for func in ['isalnum','isalpha','isdigit','islower','isupper']]