Looping through list of functions in a function in Python dynamically
我想看看是否可以运行一个函数中的函数列表。我能找到的最接近的东西就是在整个模块中循环。我只想使用预先选择的函数列表。
这是我最初的问题:
样本输入
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 的方法。 - 返回该方法本身--
。 - 然后使用
() 调用该方法,后者是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'。更有趣的是处理像
(*)与其他答案一样,函数巫术通常正是我要回答的问题,但是已经回答的问题太多了,我也可以用其他方式来回答: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) |
您可以使用内省来遍历对象的所有属性,无论它们是函数还是其他类型。
然而,您可能不想在这里这样做,因为
另外,如果不想循环使用字符串中的每个字符,也不需要循环;这些函数已经查看了整个字符串。
由于您正在循环遍历简单项列表,并试图查找函数的
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']] |