Существует ли идиома Python для оценки списка функций / выражений с коротким замыканием?

Я написал простой сценарий для решения« логической головоломки », тип головоломки из школы, где вам дают ряд правил, а затем вы должны быть в состоянии найти решение для таких проблем, как «Есть пять музыкантов по имени 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 / False с коротким замыканием без необходимости выписывать длинный список return f1 (s) и f2 (s) и f3 (s) ... ?

8
задан imz -- Ivan Zakharyaschev 2 April 2011 в 00:12
поделиться

1 ответ

Используйте выражение генератор:

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(), который возвращает следующий элемент в некоторой итерационной таблице. Это означает, что они могут делать такие полезные вещи, как чтение файла по частям, не загружая его целиком в память, или итерация до огромных целых чисел. Вы можете выполнять итерации с помощью циклов for прозрачно; Python обрабатывает это за кадром. Например, range - это генератор в Py3k.

Вы можете создавать свои собственные выражения-генераторы, используя оператор yield вместо return в определении функции:

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

и Python позаботится о сохранении состояния функции и так далее. Они великолепны!

13
ответ дан 5 December 2019 в 12:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: