Найти - Пользователи
Полная версия: Очистка потока stdin
Начало » Python для новичков » Очистка потока stdin
1
Donald522
Всем доброго времени суток.
Только начинаю изучать питон, столкнулся на днях с интересной проблемой. Сразу оговорюсь, что гуглом пользовался, поиском по форуму тоже
Писал прогу, которая должна проверять последовательность скобок на корректность. Пока решил ограничиться одним видом скобок.
Считывание решил сделать посимвольное с консоли, чтобы не вся последовательность сразу читалась, скажем, в массив, а считывалось по одному элементу и сразу обрабатывалась в алгоритме. В принципе, если читать сразу весь вход в массив и работать с ним, то ниже описанной пробемы не будет, но раз уж я с ней столкнулся, хочется разобраться.
С самим алгоритмом проблем нет, все прекрасно заработало. Проблемы начались после того, как решил все это обернуть в цикл, чтобы при вводе новой последовательности не надо было заново запускать программу, а выход сделать по заранее придуманной команде.
Собственно, сама проблема - если в какой-то момент обработки становится понятно, что последовательность некорректная (например, “(()))((())”), то происходит возврат из функции проверки, но вместо того, чотбы ожидать новую последовательность она пордолжает обрабатывать старую, с того момента, на котором произошел выход. Довольно быстро стало понятно, что проблема в том, что не происходит очистки буфера stdin.
Что предпринималось:
-sys.stdin.flush()
-попытка восстановить исходное состояние буфера при помощи буфера sys.__stdin__
-termios.tcflush(sys.stdin,termios.TCIFLUSH)
Все это оказалось безразультатно. Помогло только насильное досчитывание остатка буфера перед возвратом из функции, но похоже, что это костыль)
А еще есть просьба следующего содержания. Основная проблема сайтов с курсами и прогами в том, что они говорят только о правильности работы кода, но ничего не говорят о его качестве и читаемости. Поэтому хочется, чтобы более опытные коллеги критично оценили сам код, стиль написания.
Заранее спасибо.
#!/usr/bin/python3.4
import sys

#объявление класса Стек
class Stack:

def __init__(self):
self.items = []

#интерфейс
#проверка на пустоту
def isEmpty(self):
return self.items == []

#добавление нового элемента
def push(self, item):
self.items.append(item)

#извлечение элемента с вершины стека
def pop(self):
return self.items.pop()

#просмотр элемента на вершине стека
def peek(self):
return self.items[len(self.items)-1]

#узнать рамер стека
def size(self):
return len(self.items)

def check():

stack=Stack()
while True:
c = sys.stdin.read(1)
if c == 'e':
print('stopped')
exit(0)

if c == '\n':
break

if c == '(':
stack.push(c)

elif c == ')':
if stack.isEmpty():
sys.stdin.read()
return False

elif stack.peek() == "(":
stack.pop()

if stack.isEmpty():
return True
else:
return False

print('enter \'e\' for exit')
while True:
print(check())
FishHook
Есть же стандартные функции input для python3 и raw_input для python2, зачем напрямую с stdout работать, в чем профит?
py.user.next
Donald522
Что предпринималось:
-sys.stdin.flush()
-попытка восстановить исходное состояние буфера при помощи буфера sys.__stdin__
-termios.tcflush(sys.stdin,termios.TCIFLUSH)
Это всё неправильно.
Во-первых, функция check() должна принимать последовательность символов. Она не должна знать, откуда они приходят (с stdin, по сети или вообще генерятся из пустоты).
Во-вторых, stdin - это непрерывный поток. В нём нет данных введённых сейчас или потом. Это просто файл, который один раз заполняется и один раз читается. Там можно взять дескриптор этого файла и отслеживать на нём активность, но это неправильный путь.

Как ты узнаёшь, что две последовательности в потоке - это две последовательности, а не одна?
Donald522
py.user.next
Как ты узнаешь, что две последовательности в потоке - это две последовательности, а не одна?
По символу конца строки? У меня же есть в функции check() условие выхода из цикла.

Я так понял, что не надо с этим запариваться? Читать сразу всю последовательность в массив и передавать его функции check? А что, если последовательность будет очень большая, а ошибка будет в начале? Получается лишние траты, не очень нужные. Или я опять слишком загоняюсь?
py.user.next
Donald522
По символу конца строки?
Вообще, есть понятие “маркер конца последовательности”. Скобочная последовательность может располагаться на множестве строк.

Donald522
А что, если последовательность будет очень большая, а ошибка будет в начале?
Прочитать последовательность надо снаружи в буфер, а потом буфер подать в check(). Это в цикле делается, пока есть последовательности. И неправильные последовательности всё равно придётся дочитывать до конца, чтобы читать следующие. А сама check() делается для бесконечной последовательности.
Donald522
py.user.next
Прочитать последовательность надо снаружи в буфер, а потом буфер подать в check(). Это в цикле делается, пока есть последовательности. И неправильные последовательности всё равно придётся дочитывать до конца, чтобы читать следующие. А сама check() делается для бесконечной последовательности.
Под буфером понимается структура, которая будет объявлена мной внутри программы? Т.е. например список.
Я правильно понимаю, что в том цикле, где у меня идет вызов check(), я перед вызовом читаю последовательность в созданный мною буфер, передаю его в функцию, а при возврате из функции очищаю его?
py.user.next
Donald522
Под буфером понимается структура, которая будет объявлена мной внутри программы? Т.е. например список.
Да, типа такого.
>>> import io
>>> 
>>> def f(stream):
...     block = True
...     while block:
...         block = stream.read(10)
...         if block:
...             if not g(block):
...                 break
... 
>>> def g(s):
...     print(s * 2)
...     return 'r' not in s
... 
>>> f(io.StringIO('abcdefghijklmnopqrstuvwxyz'))
abcdefghijabcdefghij
klmnopqrstklmnopqrst
>>>
Donald522
py.user.next
Да, типа такого.
Я, если честно, подумал о более примитивной реализации, вроде такого:

while True:
buf = list(input().strip())
check(buf)
И добавить условие выхода.
С приведенными вами конструкциями пока не знаком, надо читать мануалы по модулю io. Большое спасибо.
А что можете сказать именно по стилистике написания? Хочется сразу приучаться писать грамотно.
py.user.next
Donald522
Я, если честно, подумал о более примитивной реализации, вроде такого:
Так я ж говорю, что одна скобочная последовательность может быть на нескольких строках, а input() читает не более одной.

Donald522
надо читать мануалы по модулю io
Да это просто изображение файла, чтобы как бы файл открыть, но при этом файл не открывать.

Donald522
А что можете сказать именно по стилистике написания?
У тебя там хреново с алгоритмами. Стек ещё нормально сделан, а функция check() вызывает подозрения и требует перепроверок.
Нужно сначала придумать заголовок функции (входные и выходные данные), а потом писать её содержимое, а у тебя наоборот сделано.
Привязки к stdin быть не должно (выше писал, что источних данных не должен быть ограничен), exit() быть не должно (не дело функции отвечать за завершение всей программы, в которой может оказаться эта функция), определение конца последовательности быть не должно (как бы размазываешь назначение функции, она должна только проверять одну последовательность, а она ещё и разделяет последовательности).

В общем, блок-схема не составлена до кода, из-за этого такой сырбор.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB