代码之家  ›  专栏  ›  技术社区  ›  matt b

有没有一个Python习惯用法可以用来计算带有短路的函数/表达式列表?

  •  8
  • matt b  · 技术社区  · 15 年前

    我写了一个简单的脚本来解决一个“逻辑难题”,这类难题来自学校,在那里你会得到一些规则,然后必须能够找到解决问题的方法,比如“有五个音乐家,分别是a、B、C、D和E,在一场音乐会上演奏,每个人一个接一个地演奏。。。如果A在B之前,D不是最后一个。。。什么时候谁演奏的顺序是什么?“等等。

    为了评估可能的解决方案,我将每个“规则”编写为一个单独的函数,该函数将评估可能的解决方案(简单地表示为字符串列表)是否有效,例如

    #Fifth slot must be B or D
    def rule1(solution):
        return solution[4] == 'B' or solution[4] == 'D'
    
    #There must be at least two spots between A and B
    def rule2(solution):
        returns abs(solution.index('A') - solution.index('B')) >= 2
    
    #etc...
    

    我感兴趣的是找到一种Pythonic方法来测试一个可能的解决方案是否通过了所有这些规则,并且能够在第一个规则失败后停止评估规则。

    一开始我写了最简单的事情:

    def is_valid(solution):
        return rule1(solution) and rule2(solution) and rule3(solution) and ...
    

    但这看起来很难看。我想也许我可以让这本书读得更优雅一点,有点像一个列表。。。

    def is_valid(solution)
        rules = [rule1, rule2, rule3, rule4, ... ]
        return all([r(solution) for f in rules])
    

    ... 但后来我意识到既然列表理解是在 all() 函数进行求值,这样做的副作用是根本不会短路—即使第一个规则返回,也会对每个规则进行求值 False

    所以,我的问题是:有没有一种更具Pythonic/功能性的方法来评估 True / 表达式,具有短路功能,无需写出一长串 return f1(s) and f2(s) and f3(s) ... ?

    1 回复  |  直到 14 年前
        1
  •  13
  •   SeaMonkey Katriel    7 年前

    使用 generator expression :

    rules = [ rule1, rule2, rule3, rule4, ... ]
    rules_generator = ( r( solution ) for r in rules )
    return all( rules_generator )
    

    rules = [ rule1, rule2, rule3, rule4, ... ]
    return all( r( solution ) for r in rules )
    

    生成器(基本上)是具有 .next() 方法,该方法返回某个iterable中的下一项。这意味着他们可以做一些有用的事情,比如分块读取文件而不将其全部加载到内存中,或者迭代到大整数。你可以用 for range 是Py3k的发电机。

    您可以使用 yield 语句而不是 return 在函数定义中:

    def integers():
        i = 0
        while True:
            yield i
    

    Python将处理保存函数的状态等等。他们太棒了!

    推荐文章