如何缩短此布尔表达式?

Mat*_*vis 14 python python-3.x

我是初学者制作密码生成器,需要确保密码有数字和大写字母.这个while循环的条件是多余的.for char in password出现两次.你会怎么写的?

while not (any(char.isdigit() for char in password) and (any(char.isupper() for 
char in password))):
Run Code Online (Sandbox Code Playgroud)

在循环中,它会生成另一个密码.

我的目标是更好地理解如何构造while循环的表达式,而不是以不同的方式解决问题.

Han*_*ave 22

首先,我希望网站停止使用无聊的密码要求.它们减少了密码的熵,使人们更难记住.当UI中的要求没有明确规定时,这一点尤其糟糕,因此人们可以设计一个合适的密码,而无需猜测您可能为他们设置了什么陷阱.

也就是说,你的语法比一些正则表达式实现要短一些.如果您想应用De Morgan的定律将问题分解为逻辑,这可以说是更容易推理,您可以执行以下操作(在短路时性能损失).

while all(not char.isdigit() for char in password)
       or all(not char.isupper() for char in password):
Run Code Online (Sandbox Code Playgroud)

看来你真正的问题在于这两次传球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
Run Code Online (Sandbox Code Playgroud)

单步执行此操作,它会遍历每个字符和每个条件(例如需要数字的条件)并检查是否已满足.如果是这样,它会记录该事件并检查它是否可以提前退出.最后,for循环退出的唯一可能方式是,如果在任何地方都没有满足条件password,那么我们返回False.

只是为了好玩,你可以通过使用该reduce()功能获得类似的效果(没有提前停止).它内置于Python 2.x中,您需要从functoolsPython 3.x中导入它.

while not all(reduce(
        lambda (a, b), (d, e): (a or d, b or e),
        ((c.isdigit(), c.isupper()) for c in password))):
Run Code Online (Sandbox Code Playgroud)

这有效地保持了您是否满足密码中此时的isdigit和isupper要求的运行记录.检查完整个密码后,您只需all()阅读您的标签,并确保您确实满足了这两个要求.

如果你的目标是运行时而不是像"通过数据"这样的空灵概念(不要贬低;它们在其他环境中可能很重要),你的最佳改进将来自某种类似numpy设计的高性能库矢量化您执行的查询.由于此处执行的大部分工作不是通过数据,而是在每次传递中对字符执行检查,因此消除传递数据对运行时间的影响不大.通过尽可能快地进行实际检查,您将实现最大的节省.

  • OP对密码**生成器**的密码要求绝对理智:他们需要确保生成疯狂网站接受的密码. (2认同)