Python эквивалентно методам программирования C (в то время как петли)

На языке программирования C я часто делал следующее:

while ((c = getch()) != EOF) {
 /* do something with c */
}

В Python я не нашел ничего подобного, так как мне не разрешено устанавливать переменные внутри оцениваемого выражения. Обычно мне приходится настраивать оцениваемое выражение дважды!

c = sys.stdin.read(1)
while not (c == EOF):
 # Do something with c
 c = sys.stdin.read(1)

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

while True:
 c = sys.stdin.read(1)
 if (c == EOF): break
 # do stuff with c

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

class ConditionalFileObjectReader:
 def __init__(self,fobj, filterfunc):
  self.filterfunc = filterfunc
  self.fobj = fobj
 def __iter__(self):
  return self
 def next(self):
  c = self.fobj.read(1)
  if self.filterfunc(c): raise StopIteration
  return c

for c in ConditionalFileObjectReader(sys.stdin,lambda c: c == EOF):
 print c

Все мои решения для решения простой основной проблемы программирования стали слишком сложными... У кого-нибудь есть предложение, как это сделать надлежащим образом?

Ответ 1

Я считаю, что вы хотите использовать функцию iter.

for c in iter(getch, EOF):
     #inner loop

Iter - очень универсальная функция. В этом случае вы говорите ему, чтобы он повторно вызывал getch (без аргументов) в верхней части каждого цикла до тех пор, пока getch не вернет значение счетчика, EOF.

Ответ 2

Обычно вы используете цикл for в Python:

for c in sys.stdin.read():
    # whatever

Если вы не хотите сразу буферировать весь stdin в памяти, вы также можете добавить некоторую буферизацию с меньшим буфером.

Обратите внимание, что константа EOF не существует в Python. read() просто вернет пустую строку, если в потоке не осталось данных.

Ответ 3

Можно записать гораздо более простой код вместо вашего ConditionalFileObjectReader, считая, что EOF, похоже, вас интересует, а не любое произвольное условие:

def readbytes(file):
    while True:
        c = file.read(1)
        if c == '':
            return
        yield c

for c in readbytes(sys.stdin):
    print c

Итак, у вас все еще есть "while True... break", который, кажется, является предпочтительным циклом в Python [*], но по крайней мере у вас есть только один раз, чтобы решить весь класс проблем ", как итератировать байты в файлоподобном объекте без блокировки/буферизации каждой строки", и у вас есть он в коротком цикле, который не "делает материал с помощью c" - это отдельная проблема.

Вдохновленный примером Wallacoloo с iter, как и выше, вы можете создать нечто более общее, чем iter:

def until(nextvalue, pred):
    while True:
        value = nextvalue()
        if pred(value):
            return
        yield value

for c in until(lambda: sys.stdin.read(1), lambda x: x == ''):
    print c

Я не уверен, нравится мне это или нет, но, возможно, стоит поиграть. Он пытается решить общую проблему "итерации над возвращаемыми значениями некоторой функции, пока возвращаемое значение не удовлетворяет некоторому условию".

[*] осмелюсь сказать, что питоновский эквивалент синтаксиса fancy loop на других языках?