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

Posted

技术标签:

【中文标题】动态循环遍历Python函数中的函数列表【英文标题】:Looping through list of functions in a function in Python dynamically 【发布时间】:2017-01-18 06:11:17 【问题描述】:

我想看看是否可以遍历函数中的函数列表。我能找到的最接近的事情是遍历整个模块。我只想使用预先选择的功能列表。

这是我原来的问题:

    给定一个字符串,检查每个字母,看看 5 个测试是否满足。 如果至少有 1 个字母通过检查,则返回 True。 如果字符串中的所有字母都未通过检查,则返回 False。 对于字符串中的每个字母,我们将检查这些函数:isalnum()、isalpha()、isdigit()、islower()、isupper() 每个测试的结果应该打印到不同的行。

示例输入

    qA2

示例输出(必须打印到单独的行,如果至少一个字母通过,则为 True,或者如果所有字母都未通过每次测试,则为 false):

    True
    True
    True
    True
    True

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

仅用于一项测试的代码:

    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

我尝试运行包含所有测试的循环失败:

    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

那么我该如何修复这段代码来满足上面的所有规则呢?


使用来自所有 cmets 的信息 - 此代码满足上述规则,同时动态循环每个方法。

    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 方法(我觉得这叫自省方法?)

    raw = 'ABC'

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

列表理解方法:

    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]

【问题讨论】:

为什么不将所有这些测试封装到一个名为 isValid() 的大函数中? 嗯...让我现在重新编写代码,看看我能得到什么。将使用新版本进行编辑。 一个角色如何通过 islower() 和 isupper() 测试?或者您的意思是如果任何字符与任何测试匹配,则返回 True? 所以假设字符串是'sdgSGd'。 islower 的测试将显示 True。 isupper 的测试将显示 True。两者也在不同的线路上。检查每个字母,而不是整个字符串。 @jhub1 我把你的问题缩短了很多(删除了我们在这里所说的“绒毛”),以使其更直截了当。但是,我留下了您的“cmets 的解决方案”,尽管它们在问题中也没有一席之地。我这样做只是因为它们还没有明确地出现在答案中:我建议你自己编辑它们并将它们发布在你自己的答案中(这是总结答案的好方法)。 【参考方案1】:

您在函数列表中循环的方式略有不同。这将是一种有效的方法。您需要存储在列表中的函数是 str.funcname 给出的通用字符串函数。获得这些函数列表后,您可以使用 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

示例输出:

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

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

以上是一种更 Pythonic 的方式来做到这一点,但作为一个学习工具,我编写了一个工作版本,尽可能地与你尝试的方式相匹配,以向你展示你具体哪里出错了。这里是 cmets:

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

【讨论】:

【参考方案2】:

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

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

永远不要忽视可行的最简单的事情。

现在,如果你想动态地进行——这可能是你需要的神奇关键字,你想应用这样的东西(摘自another question):

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

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

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

看这个例子:

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

【讨论】:

这并不能解决 OP 想要的问题。他/她在问题中不清楚;重新阅读 cmets 以澄清。 实际上,我相信它确实如此:它测试字符串中的每个字符,并针对每个命名方法对其进行测试。添加一个标志变量和一个 if 将完成代码,但只是给出答案并不好玩。 我的意思是第一个简单的案例。抱歉,我应该更具体一点。 啊。我试图说明一点:你可以动态地做这件事很酷,但除非你有充分的理由需要这样做,否则简单的代码会更好。 @CharlieMartin 我似乎无法让这段代码工作。现在还在努力工作 - 有什么想法吗?这是我的实现:repl.it/D4lD/4【参考方案3】:

我猜你是在验证密码复杂性,我还要说那个软件接受输入并说“假”并且没有迹象表明为什么是用户- 敌对,所以最重要的不是“如何循环嵌套 char 函数代码魔法 (*)”,而是“提供良好的反馈”,并建议更像:

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)

在线尝试at repl.it

并且正则表达式搜索在一次调用中检查字符和数字的范围,这比字符循环更整洁。

(PS。你的函数重叠;一个字符串匹配'isupper'、'islower'和'isnumeric'的字符已经覆盖了'isadigit'和'isalnum'。更有趣的是处理像!这样的字符不是大写、小写、数字或数字)。


(*) 像其他答案一样的函数魔法通常正是我会回答的,但是已经回答的太多了,我不妨换个方式回答:P

【讨论】:

在正则表达式上排名第二,但 OP 可能是 Python 的新手;投掷重新可能是压倒性的。此外,学习如何将函数视为一等公民也是一种很好的做法。 这实际上非常适合密码复杂性。没有意识到这一点。然而,它实际上只是一个 DIY-learn-Python 练习来教像我这样的初学者如何编码。不过,了解这样的代码在现实世界中的真正含义还是很棒的!【参考方案4】:

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

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

首先:不确定 i 当前在您的代码中具有哪个值被剪断,但它似乎指向字符串中的某个位置 - 这导致评估单个字符,而不是整个字符串 raw .

第二:当你建立你的列表时,你已经在调用你想要插入的方法,这导致插入的不是函数本身,而是它们的返回值(这就是为什么你会看到所有这些 打印语句中的真实值)。

尝试如下更改您的代码:

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

【讨论】:

所以我的想法是创建两个循环。第一个循环,使用 f,遍历函数。第二个循环使用 i 来索引原始数据,它实际上返回每个字母以检查 f 循环中的每个函数。 @jhub1 我刚刚更新了我的答案,以解释您在具体尝试中出错的地方;你实际上并不遥远!请检查一下。 @gowrath 我是一个慢速编码器 - 仍在研究所有概念,包括您的帖子(for 循环构造、re 模块、getattr 等)。找到了 any() 的巧妙用法,因此也可以使用它。我知道这太复杂了,但尝试所有其他东西很有趣! @gowrath 这看起来怎么样?我将您的方法和任何方法结合起来,以获得一些真正缩短的代码。 repl.it/D4kO @jhub1 看起来棒极了。做得很好(y)。如果您认为您的问题已得到回答,请将回复标记为已回答,这样它就不会留在未回答部分中。【参考方案5】:

回答原来的问题:

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

【讨论】:

不区分哪个函数返回true。 确实如此。我回答时的问题并没有说清楚。【参考方案6】:

由于您正在遍历简单项目列表并尝试查找函数中的all 是否具有any 有效结果,因此您可以简单地定义要在输入上调用的函数列表并将其返回。这是您要实现的目标的一个相当 Python 的示例:

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

测试一下:

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

【讨论】:

【参考方案7】:

您可以使用introspection 循环访问对象的所有属性,无论它们是函数还是其他类型。

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

此外,如果您不想循环,则不需要遍历字符串的每个字符;这些函数已经查看了整个字符串。

【讨论】:

对不起!我写了一个可怕的描述。代码提示要求检查每个字母,这就是我在一堆循环中苦苦挣扎的原因。因此,例如 - 'dasfsdfX' 将返回 True 进行上层检查,'asdfa' 将返回 False。【参考方案8】:

查看这个针对您的问题的单线解决方案。这个问题来自 HackerRank。我使用内置的 getattr 函数遍历函数列表。

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

【讨论】:

以上是关于动态循环遍历Python函数中的函数列表的主要内容,如果未能解决你的问题,请参考以下文章

python基础03-循环结构及函数基础

python中的for i in range怎么用

python中的for i in range怎么用

对于python中的循环效率

python中的enumerate()函数的用法

Python循环遍历列表并创建动态变量