Небольшая избыточность кода в циклах while (не чистая)

Итак, в Python (хотя я думаю, что это может быть применено ко многим языкам), я часто встречаюсь с чем-то вроде этого:

the_input = raw_input("what to print?\n")
while the_input != "quit":
    print the_input
    the_input = raw_input("what to print?\n")

Возможно, я слишком придирчив, но мне не нравится, как строка the_input = raw_input("what to print?\n") должна повторяться. Это уменьшает ремонтопригодность и организацию. Но я не вижу обходных путей для избежания дублирования кода, не обостряя проблему. На некоторых языках я мог бы написать что-то вроде этого:

while ((the_input=raw_input("what to print?\n")) != "quit") {
    print the_input
}

Это определенно не Pythonic, и Python даже не позволяет назначать в условиях цикла AFAIK.

Этот действительный код исправляет избыточность,

while 1:
    the_input = raw_input("what to print?\n")
    if the_input == "quit":
        break
    print the_input

Но это тоже не совсем правильно. while 1 означает, что этот цикл будет работать вечно; Я использую цикл, но даю ему поддельное условие и помещая в него реальный.

Неужели я слишком придирчив? Есть лучший способ сделать это? Возможно, для этого существует некоторая языковая конструкция, о которой я не знаю?

Ответ 1

Подумайте итераторы - например, в этом конкретном случае:

for the_input in iter(lambda: raw_input('what to print?\n'), 'quit'):
    print the_input

Большинство циклов в Python, за исключением самых нижних уровней абстракций, лучше всего реализуются как циклы for с помощью какого-то подрывного итератора, который захватывает "логику цикла" - встроенный iter может помочь (например, здесь), иногда genexps (генераторные выражения) может, иногда стандартный библиотечный модуль itertools приходит на помощь.

Чаще всего вы выберете код пользовательских функций генератора (те, которые используют yield), или несколько раз (когда вам нужно действительно сложное управление состоянием) пользовательский класс итератора (один из которых определяет специальный метод __iter__ как return self, и next [[или __next__ в последних версиях Python]], чтобы вернуть "следующее значение из итерации).

Захват логики цикла за исключением того, что вы делаете на разных элементах, последовательно созданных самим циклом, здесь является помощником-абстракцией клавиш.