我是制作密码生成器的初学者,需要确保密码同时包含数字和大写字母。这个 while 循环的条件是多余的。 for char in password
出现两次。你会怎么写?
while not (any(char.isdigit() for char in password) and (any(char.isupper() for
char in password))):
在循环中它生成另一个密码。
我的目标是更好地理解如何构造 while 循环的表达式,而不是用不同的方式解决问题。
最佳答案
首先,我希望网站停止对空洞的密码要求。它们降低了密码的熵并使人们更难记住。如果要求没有在 UI 中明确列出,这样人们就可以设计一个合适的密码,而无需猜测您可能为他们设置的陷阱,这尤其糟糕。
也就是说,您的语法比某些正则表达式实现要短得多。如果您想应用德摩根定律将问题分解成可以说更容易推理的逻辑,您可以执行以下操作(在短路方面有性能损失)。
while all(not char.isdigit() for char in password)
or all(not char.isupper() for char in password):
看来你真正的问题是两次通过 password
。有趣的是,正则表达式方法有同样的问题,隐藏在一些额外的语法后面。如果您愿意为了通用性、短路能力和一次通过数据而牺牲解决方案的简洁性,那么您可以像这样将条件提取到它自己的方法中:
def satisfies(password, *conditions):
flags = [False] * len(conditions)
for c in password:
for i, cond in enumerate(conditions):
if cond(c):
flags[i] = True
if all(flags):
return True
return False
while satisfies(password, str.isdigit, str.isupper):
pass
逐步执行此过程,它会遍历每个字符和每个条件(例如需要数字的条件)并检查是否已满足。如果是这样,它会记录该事件并检查它是否可以提前退出。最后,for
循环退出的唯一可能方式是如果 password
中的任何地方都没有满足条件,所以我们返回 False
.
只是为了好玩,您可以使用 reduce()
函数获得类似的效果(无需提前停止)。它内置于 Python 2.x 中,您需要从 Python 3.x 中的 functools
导入它。
while not all(reduce(
lambda (a, b), (d, e): (a or d, b or e),
((c.isdigit(), c.isupper()) for c in password))):
这有效地记录了您是否满足密码中的 isdigit 和 isupper 要求。检查整个密码后,您只需使用 all()
来读取您的记录并确保您确实满足了这两个要求。
如果您的目标是运行时间而不是像“传递数据”这样的空灵概念(不是贬低;它们在其他情况下可能很重要),那么您最好的改进将来自某种高性能numpy
之类的库旨在对您执行的查询进行矢量化。由于此处执行的大部分工作不是遍历数据,而是每次遍历中对字符执行的检查,因此消除遍历数据对运行时间不会有太大帮助。通过尽快进行实际检查,您将实现最大的节省。
关于python - 如何缩短这个 bool 表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51870069/