Условие назначения в Python во время цикла

#python #loops #while-loop #conditional-statements

#python #циклы #во время цикла #условные операторы

Вопрос:

В C можно сделать

 while( (i=a) != b ) { }
  

но в Python, похоже, это невозможно.

 while (i = sys.stdin.read(1)) != "n":
  

генерирует

     while (i = sys.stdin.read(1)) != "n":
         ^
SyntaxError: invalid syntax
  

( ^ должно быть на = )

Есть ли обходной путь?

Комментарии:

1. о, это неудобно… как readline() сравнить с raw_input() ?

2. @tekknolagi Он, вероятно, не получил ваш комментарий. Хорошей идеей будет пинговать пользователя, добавляя @name его в текст комментария.

3. @Йохенрицель видишь мой комментарий? извините 🙂

4. Причина, по которой это не работает в Python, заключается в том, что присваивания являются операторами , а не выражениями — это просто из-за правил создания грамматики.

5. Объяснение см. В разделе Часто задаваемые вопросы по Python: почему я не могу использовать присваивание в выражении? . Он поддерживает итераторы или while True вместо этого.

Ответ №1:

Начиная Python 3.8 с и введения выражений присваивания (PEP 572) ( := operator), теперь стало возможным записывать значение выражения (здесь sys.stdin.read(1) ) в качестве переменной, чтобы использовать его в теле while :

 while (i := sys.stdin.read(1)) != 'n':
  do_smthg(i)
  

Это:

  • Присваивает sys.stdin.read(1) переменной i
  • Сравнивает i с n
  • Если условие проверено, вводится while тело, в котором i можно использовать

Комментарии:

1. Да, и спасибо! Лучший ответ здесь.

Ответ №2:

Используйте break:

 while True:
    i = sys.stdin.read(1)
    if i == "n":
       break
    # etc...
  

Комментарии:

1. @FalconMomot Мне это кажется вполне разумным шаблоном. Какое имеет значение, где цикл прерывается? Либо условие завершения произойдет, либо его не будет. Если i == "n" этого не происходит внутри цикла (вызывая разрыв), это также не произошло бы в аргументе условия цикла while.

Ответ №3:

Вы можете выполнить это с помощью встроенной функции iter() , используя метод вызова с двумя аргументами:

 import functools
for i in iter(fuctools.partial(sys.stdin.read, 1), 'n'):
    ...
  

Документация для этого:

iter(o[, sentinel])

Если задан второй аргумент, sentinel , то o должен быть вызываемым объектом. Созданный в этом случае итератор будет вызывать o без аргументов для каждого вызова своего next() метода; если возвращаемое значение равно sentinel , StopIteration будет повышено, в противном случае значение будет возвращено.

Одним из полезных применений второй формы iter() является чтение строк файла до тех пор, пока не будет достигнута определенная строка. Следующий пример считывает файл до тех readline() пор, пока метод не вернет пустую строку:

 with open('mydata.txt') as fp:
    for line in iter(fp.readline, ''):
        process_line(line)
  

Ответ №4:

Версия без functools :

 for i in iter(lambda: sys.stdin.read(1), 'n'):
  

Ответ №5:

Лично мне нравятся ответы imm и метки break , но вы также могли бы сделать:

 a = None
def set_a(x):
    global a
    a = x
    return a

while set_a(sys.stdin.read(1)) != 'n':
    print('yo')
  

хотя я бы не рекомендовал это.