2014-09-12 5 views
1

В настоящее время я разрабатываю бот python, в котором у меня есть код с классом, который имеет методы итератора.Iterator freezing

buffer = [] 
def __iter__(self): 
    return self 
def __next__(self): 
    incoming = str(self.irc.recv(1024), encoding='utf-8').split("\r\n") 
    self.buffer += incoming 
    last = self.buffer.pop(0) #This implements a FI-FO queue 
    #perform operations to extract commands etc. 
    return [message,command,trail] 

Я звоню этот класс в итератора, который в основном выглядит как:

for command in connection: #Connection is the name of the above class 
    print(command) 

То, что я наблюдения является то, что первые 3 элемента очереди повторяются через, а затем все остальное просто оставлены там, в очереди, не обрабатываются до тех пор, пока новый элемент не войдет в очередь, после чего первый элемент в очереди уйдет (как будто последний элемент вытолкнул первый). Я не уверен, что это связано с итераторами, и я не должен использовать их для выполнения этой задачи (если нет, то, что я должен использовать), или это еще одна проблема. Спасибо за любую помощь, Kunc.

+2

'irc.recv' выглядит как нечто, что может привести к блокировке потока, убедитесь, что вы не ожидаете данных. – user2085282

+1

Действительно ли вы хотите, чтобы 'buffer' был атрибутом класса, общим для всех экземпляров этого класса? Это похоже на очень плохую идею для чего-то подобного ... – abarnert

+1

Да. Я исправил это теперь, добавив оператор if вокруг функции recv, проверяя, что буфер пуст, прежде чем добавлять к нему. – Kunc

ответ

3

Ваша главная проблема заключается в следующем:

Каждый раз, когда вы заранее свой итератор, вы recv один или несколько линий, то return только последний из них. Поэтому в какой-то момент у вас будут все строки, которые складываются в вашей очереди, а затем попытайтесь получить еще один кусок данных, который не будет готов, так что вы просто заблокируете навсегда.

Представьте другую сторону послал эти три буфера:

'abc\ndef\nghi\n' 
'jkl\n' 
'mno\nprs\n' 

Таким образом, в первый раз через, вы будете получать 'abc\ndef\nghi\n', разделить, что на три линии, и вернуться 'abc'.

Во второй раз вы получите 'jkl\n', разделите это на еще одну строку и добавьте его и верните 'def'.

В третий раз вы получите 'mno\nprs\n', разделите это на две другие строки и добавьте их и верните 'ghi'.

В четвертый раз вы будете ждать вечную, чтобы получить следующую строку.

Что вам нужно сделать здесь, это не recv еще раз, пока вы не вышли из строя.


Однако у вас есть вторая проблема. Нет абсолютно ничего, что гарантирует, что каждый буфер закончится на новой строке. Таким образом, вы можете легко разделить линии пополам. То, что вы хотите сделать что-то вроде этого:

def __init__(self): 
    self.lines, self.buf = [], '' 
    # existing code 
def __next__(self): 
    if not self.lines: 
     newbuf = str(self.irc.recv(1024), encoding='utf-8') 
     if newbuf: 
      self.buf += newbuf 
      self.lines = self.buf.split("\r\n") 
      self.buf = self.lines.pop() 
    last = self.lines.pop(0) 
    # etc. 

Или, более просто:

def __init__(self): 
    # existing code 
    self.rfile = self.irc.makefile('r', encoding='utf-8', newline='\r\n') 
def close(self): 
    self.rfile.close() 
    # existing code 
def __next__(self): 
    return self.rfile.readline() 

Поскольку код, который я написал именно то, что socket.makefile делает, за исключением того, что он заворачивает его в полном файлоподобном объекте (io.TextIOWrapper, в данном случае).