Назначить переменную в условии цикла while в Python?

Я только что наткнулся на этот кусок кода

while 1:
    line = data.readline()
    if not line:
        break
    #...

и подумал, должен сделать это лучше, чем использовать бесконечный цикл с break.

Итак, я попытался:

while line = data.readline():
    #...

и, очевидно, получил ошибку.

Есть ли способ избежать использования break в этой ситуации?

Редактировать:

В идеале вам не следует повторять readline дважды... ИМХО, повторение еще хуже, чем просто break, особенно если утверждение сложное.


person user541686    schedule 08.07.2011    source источник
comment
Хотя это хороший вопрос, и я думаю, что решение for line in data хорошо подходит для этой конкретной проблемы, я не думаю, что с идиомой while True: ... break что-то не так. Не бойтесь этого. :-)   -  person Kirk Strauser    schedule 09.07.2011
comment
Эти ответы предоставляют альтернативы присваиванию в условном выражении цикла while, но на самом деле не отвечают на вопрос: есть ли способ выполнить присваивание в цикле while? Я сталкиваюсь с той же проблемой, пытаясь сделать while (character = string[i]): я знаю, что цикл for - лучший способ перебирать строку, но мое условие на самом деле гораздо сложнее, чем это, и я хочу сделать это присваивание правой частью или внутри условного оператора.   -  person    schedule 09.09.2013
comment
@KirkStrauser Проблема с конструкцией разрыва заключается в том, что она использует четыре строки для выражения чего-либо, что другие языки могут сделать всего одной строкой. Однако правильно делает. Ни один из ответов, данных до сих пор, не предоставил лучшего решения общего назначения. Они либо работают только с итераторами, либо дублируют присваивание, что хуже трех лишних строчек кода для версии с разрывом.   -  person kasperd    schedule 21.11.2014


Ответы (11)


Если вы не делаете ничего более сложного с данными, например, читаете больше строк позже, всегда есть:

for line in data:
    ... do stuff ...
person Ned Batchelder    schedule 08.07.2011
comment
Я пытался играть в Stump The Sushi Eater, думая о типе объекта data, который мог бы поддерживать .readline(), но не __iter__(). Я рисую пустышку. Вы знаете какие-нибудь навскидку? - person Kirk Strauser; 09.07.2011
comment
Разве для этого не требуется сначала прочитать весь файл в память? Это не кажется применимым для больших файлов. (Особенно, если файл больше, чем может вместить ваша оперативная память!) - person ThorSummoner; 15.10.2014
comment
Если data является файловым объектом (это странное имя, но именно так его использовал OP), то весь файл не будет считан в память. for line in data будет перебирать строки, считывая их по мере необходимости. - person Ned Batchelder; 15.10.2014
comment
@NedBatchelder: согласно документам на docs.python.org/2/ library/stdtypes.html#file.next - и мой неудачный опыт - указатель файла находится не там, где вы ожидаете (например, для data.tell()) с for line in data, и даже может быть в конце файла даже до того, как будет прочитана последняя строка. Таким образом, он не совсем читает их по мере необходимости, если вы рассчитываете на python/os для учета того, где вы находитесь в файле. - person mpag; 05.01.2017
comment
@mpag Определенно нет гарантии (и я не имел в виду, что была), что каждая строка читается именно так, как это необходимо. Я возражал против того, что весь файл будет прочитан в память. Если вы выполняете итерацию по строкам, вы не можете делать никаких предположений о том, где находится указатель файла. - person Ned Batchelder; 06.01.2017
comment
Это все еще верно для python 3? - person winni2k; 17.08.2017

Начало Python 3.8 и введение выражений присваивания (PEP 572) (оператор := ), теперь можно зафиксировать значение условия (data.readline()) цикла while в виде переменной (line), чтобы повторно использовать его в теле цикла:

while line := data.readline():
  do_smthg(line)
person Xavier Guihot    schedule 27.04.2019

Попробуйте этот, работает для файлов, открытых с помощью open('filename')

for line in iter(data.readline, b''):
person Niklas Claesson    schedule 17.10.2012
comment
+1 за пример в документации ядра python: docs.python.org/2 /library/functions.html#iter - person ThorSummoner; 15.10.2014

Это не намного лучше, но я обычно делаю так. Python не возвращает значение при присвоении переменной, как другие языки (например, Java).

line = data.readline()
while line:
    # ... do stuff ... 
    line = data.readline()
person dfb    schedule 08.07.2011
comment
Я не большой поклонник этого, особенно если ... do stuff ... значителен, так как он требует, чтобы вы помнили о потоке всего цикла, когда вы его копаете. Например, если вы добавите что-то вроде if line.startswith('foo'): continue позже, не понимая, что line обновляется только в самом конце, то вы случайно создали бесконечный цикл. - person Kirk Strauser; 09.07.2011
comment
@Kirk - Отчасти я согласен, но альтернативы не намного лучше. В идеале класс, который вы используете, реализует генератор, и вы можете просто использовать цикл for, но есть определенные случаи, когда вам нужен цикл while (например, 'while cur_time>expected_time:'). Я не знаю, намного ли пост ОП лучше, но я полагаю, что это вопрос мнения :) - person dfb; 09.07.2011
comment
Классический цикл while, понятный программисту любого уровня. Вероятно, лучший выбор для будущего обслуживания. - person Kim; 24.01.2019
comment
@Kirk Strauser Можно утверждать, что если ... do stuff ... так долго, что вы потеряли представление о том, что происходит в вашем цикле, то, вероятно, вы делаете это неправильно. - person arkan; 26.04.2019

Нравиться,

for line in data:
    # ...

? Это во многом зависит от семантики семантики строки чтения объекта data. Если data является объектом file, это сработает.

person Kirk Strauser    schedule 08.07.2011

Начиная с Python 3.8 (который реализует PEP-572) этот код теперь действителен. :

while line := data.readline():
   # do something with line 
person Rich L    schedule 05.11.2019

for line in data:
    ... process line somehow....

Будет перебирать каждую строку в file, а не использовать while. По моему опыту (в Python) это гораздо более распространенная идиома для задачи чтения файла.

На самом деле data не обязательно должен быть файлом, а просто предоставлять итератор.

person shelhamer    schedule 08.07.2011

Вы можете сделать:

line = 1
while line:
    line = data.readline()
person brandon    schedule 08.07.2011
comment
Это выполнит тело цикла еще раз, чем предполагалось. - person kasperd; 21.11.2014

Если у data есть функция, которая возвращает итератор вместо readline (скажем, data.iterate), вы можете просто сделать:

for line in data.iterate():
    #...
person TorelTwiddler    schedule 08.07.2011
comment
Не делайте этого, если только вы не знаете, что data крошечный (и на самом деле даже не тогда), поскольку .readlines() загружает все содержимое в ОЗУ, но на самом деле ничего не покупает вам взамен. - person Kirk Strauser; 09.07.2011
comment
Все должно работать нормально, если функция возвращает итератор вместо всего списка, верно? - person TorelTwiddler; 09.07.2011
comment
Да, но я не видел .readlines(), реализованного таким образом. Документы для file.readlines() говорят, что он будет [r] читать до EOF с использованием readline() и возвращать список, содержащий строки, прочитанные таким образом. - person Kirk Strauser; 09.07.2011
comment
Мне больше нравится этот ответ. :-) Однако обычное имя для iterate__iter__, и тогда вы можете переписать цикл как for line in data. - person Kirk Strauser; 09.07.2011
comment
Верно, но я оставлю это так, так как уже есть 4 других ответа, в которых есть for line in data. = Д - person TorelTwiddler; 09.07.2011

Если data является файлом, как указано в других ответах, использование for line in file будет работать нормально. Если данные — это не файл, а случайный объект чтения данных, то следует реализовать его как итератор, реализовав методы __iter__ и next.

Метод next должен к чтению проверить, есть ли еще данные, и если нет, поднять StopIteration. Если вы это сделаете, вы можете продолжать использовать идиому for line in data.

person rafalotufo    schedule 08.07.2011

Согласно Часто задаваемые вопросы из документации Python, перебор ввода с помощью конструкции for или запуск бесконечного цикла while True и использование оператора break для его завершения, являются предпочтительными и идиоматическими способами итерации.

person Mr. Deathless    schedule 25.08.2013