简体   繁体   English

动态地循环遍历Python中函数的函数列表

[英]Looping through list of functions in a function in Python dynamically

I'd like to see if it's possible to run through a list of functions in a function. 我想看看是否可以在函数中运行函数列表。 The closest thing I could find is looping through an entire module. 我能找到的最接近的东西是循环整个模块。 I only want to use a pre-selected list of functions. 我只想使用预先选择的功能列表。

Here's my original problem: 这是我原来的问题:

  1. Given a string, check each letter to see if any of the 5 tests fulfill. 给定一个字符串,检查每个字母以查看是否满足5个测试中的任何一个。
  2. If a minimum of 1 letter passes a check, return True. 如果至少1个字母通过检查,则返回True。
  3. If all letters in the string fails the check, return False. 如果字符串中的所有字母都未通过检查,则返回False。
  4. For each letter in the string, we will check these functions: isalnum(), isalpha(), isdigit(), islower(), isupper() 对于字符串中的每个字母,我们将检查这些函数: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
    True

I wrote this for one test. 我写了一个测试。 Of course I could just write 5 different sets of code but that seems ugly. 当然我可以写出5组不同的代码,但这看起来很难看。 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

So how do I fix this code to fulfill all the rules up there? 那么如何修复此代码以实现所有规则呢?


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?) getattr方法(我认为这被称为内省方法?)

    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]

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. 您需要存储在列表中的函数是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! 一旦你有了这些函数列表,就可以使用for循环遍历它们,并将其视为普通函数!

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++. 另外我注意到你似乎使用索引进行迭代,这让我觉得你可能会来自像C / C ++这样的语言。 The for in loop construct is really powerful in python so I would read up on it (y). for循环结构在python中非常强大,所以我会读它(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. 上面是一个更加pythonic的方式来做到这一点,但作为一个学习工具,我写了一个工作版本,与你试图尽可能多地做到这一点,以显示你特别错误的地方。 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

Okay, so the first question is easy enough. 好的,所以第一个问题很简单。 The simple way to do it is just do 这样做的简单方法就是这样做

def foo(raw):
  for c in raw:
    if c.isalpha(): return True
    if c.isdigit(): return True
    # the other cases
  return False

Never neglect the simplest thing that could work. 永远不要忽视可行的最简单的事情。

Now, if you want to do it dynamically -- which is the magic keyword you probably needed, you want to apply something like this (cribbed from another question ): 现在,如果你想动态地做 - 这是你可能需要的魔术关键词,你想要应用这样的东西(从另一个问题中抄袭):

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

Warning, this is untested code meant to give you the idea. 警告,这是未经测试的代码,旨在为您提供这个想法。 The key notion here is that the methods of an object are attributes just like anything else, so, for example getattr("a", "isalpha")() does the following: 这里的关键概念是对象的方法就像其他任何东西一样属性,因此,例如getattr("a", "isalpha")()执行以下操作:

  • Uses getattr to search the attributes dictionary of "a" for a method named isalpha 使用getattr在名为isalpha的方法中搜索"a"的属性字典
  • Returns that method itself -- <function isalpha> 返回该方法本身 - <function isalpha>
  • then invokes that method using the () which is the function application operator in Python. 然后使用()这是Python中的函数应用程序运算符来调用该方法。

See this example: 看这个例子:

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

To answer the original question: 回答原来的问题:

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

All the other answers are correct, but since you're a beginner, I want to point out the problem in your code: 所有其他答案都是正确的,但由于您是初学者,我想在您的代码中指出问题:

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

First: Not sure which value i currently has in your code snipped, but it seems to point somewhere in the string - which results in single characters being evaluated, not the whole string raw . 第一:不确定的代码中当前有哪个值被剪切,但它似乎指向字符串中的某个位置 - 这导致单个字符被评估,而不是整个字符串raw

Second: When you build your list, you are already calling the methods you want to insert, which has the effect that not the functions themself get inserted, but their return values (that's why you're seeing all those True values in your print statement). 第二:当你构建你的列表时,你已经调用了你要插入的方法,这个方法不是自己插入函数,而是它们的返回值(这就是为什么你在print语句中看到所有那些True值的原因) )。

Try changing your code as follows: 尝试更改代码,如下所示:

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

I'm going to guess that you're validating password complexity, and I'm also going to say that software which takes an input and says "False" and there's no indication why is user-hostile, so the most important thing is not "how to loop over nested char function code wizardry (*)" but "give good feedback", and suggest something more like: 我猜你要验证密码的复杂性,而且我也会说那个接受输入并说“False”的软件而且没有任何迹象表明为什么用户是敌对的,所以最重要的不是“如何循环嵌套的char函数代码wizardry(*)”但“给出了很好的反馈”,并建议更像:

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)

Try online at repl.it 在repl.it上在线试用

And the regex searching checks ranges of characters and digits in one call, which is neater than a loop over characters. 正则表达式搜索在一次调用中检查字符和数字的范围,这比字符循环更整洁。

(PS. your functions overlap; a string which has characters matching 'isupper', 'islower' and 'isnumeric' already has 'isadigit' and 'isalnum' covered. More interesting would be to handle characters like ! which are not upper, lower, digits or alnum). (PS。你的函数重叠;一个字符串,其字符匹配'isupper','islower'和'isnumeric'已经有'isadigit'和'isalnum'覆盖。更有趣的是处理像!这些不是上层,下层的字符,数字或alnum)。


(*) function wizardry like the other answers is normally exactly what I would answer, but there's so much of that already answered that I may as well answer the other way instead :P (*)像其他答案一样的功能魔法通常就是我要回答的内容,但是有很多已经回答的内容,我可能会回答其他方式:P

Since you are looping through a list of simple items and trying to find if all of the functions has any valid results, you can simply define the list of functions you want to call on the input and return that. 由于您循环遍历简单项的列表并尝试查找是否all函数都有any有效结果,因此您只需定义要在输入上调用的函数列表并返回该函数。 Here is a rather pythonic example of what you are trying to achieve: 这是你想要实现的一个相当pythonic的例子:

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

Test it out: 测试出来:

>>> 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
>>> 

You can use introspection to loop through all of an object's attributes, whether they be functions or some other type. 您可以使用内省循环遍历所有对象的属性,无论它们是函数还是其他类型。

However you probably don't want to do that here, because str has lots of function attributes, and you're only interested in five of them. 但是你可能不想在这里这样做,因为str很多函数属性,而你只对它们中的五个感兴趣。 It's probably better to do as you did and just make a list of the five you want. 这可能比你做的更好,只需列出你想要的五个。

Also, you don't need to loop over each character of the string if you don't want to; 另外,如果你不想,你不需要遍历字符串的每个字符; those functions already look at the whole string. 那些函数已经查看了整个字符串。

Check out this one-line solution for your problem. 查看这个针对您的问题的单行解决方案。 That problem is from HackerRank. 那个问题来自HackerRank。 I loop through a list of functions using the built-in getattr function. 我使用内置的getattr函数遍历函数列表。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM