retrlines(self, cmd, callback=None) unbound ftplib.FTP method
Retrieve data in line mode. A new port is created for you.
Args:
cmd: A RETR, LIST, NLST, or MLSD command.
callback: An optional single parameter callable that is called
for each line with the trailing CRLF stripped.
[default: print_line()]
Returns:
The response code.
Как можно передать ей такой callback, чтобы написать
def ftplines(ftp, filename):
. . .
callback = . . .
ftp.retrlines("RETR " + filename, callback)
for l in ftplines(ftp, "/etc/shadow"):
. . .
т. е., заставить результат работать как генератор?
14.07.09 17:19: Перенесено из 'Декларативное программирование'
Здравствуйте, Roman Odaisky, Вы писали:
RO>В модуле ftplib есть такая функция: RO>... RO>Как можно передать ей такой callback, чтобы написать RO>т. е., заставить результат работать как генератор?
afaik, в обычном Питоне это невозможно. Это возможно в Scheme(см. continuations), Lua (см. coroutines), Stackless Python (см. tasklets + channels).
Здравствуйте, SergH, Вы писали:
SH>Компилятор не поймёт и не оценит. Куда ему девать возвращаемое ftplines значение?
Принципиальной проблемы — куда девать — нет. У корутины может быть множество промежуточных результатов и один конечный. Проблема только в ограниченной семантике корутин в Питоне.
Здравствуйте, palm mute, Вы писали:
PM>Принципиальной проблемы — куда девать — нет. У корутины может быть множество промежуточных результатов и один конечный. Проблема только в ограниченной семантике корутин в Питоне.
Принципиальной нет, но есть синтаксическая.
Это всё-таки не вполне полноценные корутины, насколько я понимаю. Питоновская корутина должна возвращать итератор, т.е. объект с предопределённым интерфейсом, у него потом можно вызывать функцию next, а в конце он выбросит исключение. Для возвращаемого значения тут места нет.
А yield это просто синтаксический сахар для всего этого.
Здравствуйте, Roman Odaisky, Вы писали: RO>т. е., заставить результат работать как генератор?
А как в питоне с многопоточностью? Можно было бы вынести retrlines с коллбеком в один поток (он бы блокировался на ipc), а в другом сделать генератор (который бы получал от первого потока строку и разблокировал бы колллбек).
Здравствуйте, Mr.Cat, Вы писали:
MC>А как в питоне с многопоточностью? Можно было бы вынести retrlines с коллбеком в один поток (он бы блокировался на ipc), а в другом сделать генератор (который бы получал от первого потока строку и разблокировал бы колллбек).
Здравствуйте, SergH, Вы писали:
SH>Это всё-таки не вполне полноценные корутины, насколько я понимаю. Питоновская корутина должна возвращать итератор, т.е. объект с предопределённым интерфейсом, у него потом можно вызывать функцию next, а в конце он выбросит исключение. Для возвращаемого значения тут места нет.
Здравствуйте, FR, Вы писали:
SH>>Это всё-таки не вполне полноценные корутины, насколько я понимаю. Питоновская корутина должна возвращать итератор, т.е. объект с предопределённым интерфейсом, у него потом можно вызывать функцию next, а в конце он выбросит исключение. Для возвращаемого значения тут места нет.
FR>Так начиная с 2.5 yield в обе стороны работает http://www.python.org/dev/peps/pep-0342/
Так это поможет всё-таки переделать интерфейс на коллбэках в интерфейс на генераторах?
Здравствуйте, Roman Odaisky, Вы писали:
FR>>Так начиная с 2.5 yield в обе стороны работает http://www.python.org/dev/peps/pep-0342/
RO>Так это поможет всё-таки переделать интерфейс на коллбэках в интерфейс на генераторах?
Нет, это всего лишь позволяет организовать двусторонний обмен сообщениями между генератором и вызывающим кодом.
Здравствуйте, SergH, Вы писали:
SH>Это всё-таки не вполне полноценные корутины, насколько я понимаю. Питоновская корутина должна возвращать итератор, т.е. объект с предопределённым интерфейсом, у него потом можно вызывать функцию next, а в конце он выбросит исключение. Для возвращаемого значения тут места нет.
Неполноценность питоновских генераторов в другом — ограниченность контекста одной процедурой, тем хорошо раскрыта в Lua wiki.
SH>А yield это просто синтаксический сахар для всего этого.
С вашего позволения придерусь к терминологии, т.к. тут на РСДН принятно слишком вольно обращаться с термином "синтаксический сахар". О синтаксическом сахаре можно говорить в том случае, когда есть тривиальное синтаксическое преобразование, превращающее программу с сахаром в программу без сахара. Например, for-loop тривиально преобразуется в while-loop (используя __iter__, next и StopIteration). yield — примитив языка.
Здравствуйте, palm mute, Вы писали:
PM>Неполноценность питоновских генераторов в другом — ограниченность контекста одной процедурой, тем хорошо раскрыта в Lua wiki.
Насколько я понял, это о том же.
SH>>А yield это просто синтаксический сахар для всего этого. PM>С вашего позволения придерусь к терминологии, т.к. тут на РСДН принятно слишком вольно обращаться с термином "синтаксический сахар". О синтаксическом сахаре можно говорить в том случае, когда есть тривиальное синтаксическое преобразование, превращающее программу с сахаром в программу без сахара. Например, for-loop тривиально преобразуется в while-loop (используя __iter__, next и StopIteration). yield — примитив языка.
Согласен, неаккуратно выразился.
Я имел ввиду, что снаружи функция, которая использует yield неотличима от функции, возвращающей итератор. Т.е. если исключить то, как генерируется последовательность, ничего нового не вводится. Компилятор обнаруживает в теле функции слово "yield" и всё понимает сам. Ну, фактически, он оборачивает функцию в корутину, но делает это незаметно, "корутина" это деталь реализации, а не понятие, которое может использовать программист.
В Lua же вытащили её наружу. В результате функцию нужно явно завернуть в корутину (если я прввильно понял текст, Lua я не знаю). И поведение корутины ни с чем другими не спутаешь.
Т.е. в Питоне более удобно решен частный случай проблемы.
Здравствуйте, FR, Вы писали:
FR>Здравствуйте, Mr.Cat, Вы писали:
MC>>А как в питоне с многопоточностью? Можно было бы вынести retrlines с коллбеком в один поток (он бы блокировался на ipc), а в другом сделать генератор (который бы получал от первого потока строку и разблокировал бы колллбек).
FR>Можно, но бесполезно из-за GIL.
Для данной задачи GIL пофиг. Всё равно он хотел исполнять это в одной нитке, так что две которые аккуратно переключаются — будут исполнять то же самое с минимумом оверхеда.
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, neFormal, Вы писали:
CS>Сугубо для сравнения вот функция в TIScript которая итерирует все строки в файле path удовлетворяющих template
Оно примерно также и будет в питоне тоже, вопрос был в том чтобы итерировать класс который для этого не предназначен и превратить принимаемые им callback в итератор.
Здравствуйте, FR, Вы писали:
FR>Оно примерно также и будет в питоне тоже, вопрос был в том чтобы итерировать класс который для этого не предназначен и превратить принимаемые им callback в итератор.
А... ну тогда как-то так:
function linesOfResponse( cmd )
{
var lines = [];
function receiver(line) { lines.push(line); }
retrlines(cmd, receiver);
return function() { while(lines.length) return lines.shift(); }
}
for( var line in linesOfResponse( "LIST" ) )
stdout.printf("%s\n", line);
Здравствуйте, FR, Вы писали:
CS>>Сугубо для сравнения вот функция в TIScript которая итерирует все строки в файле path удовлетворяющих template
FR>Оно примерно также и будет в питоне тоже, вопрос был в том чтобы итерировать класс который для этого не предназначен и превратить принимаемые им callback в итератор.
Вот на луа с корутинами, примерно как palm mute выше писал:
-- (* lines-like.lua *)local co = coroutine
-- (* linesLike :: str, str, callback -> thunk *)local functionlinesLike(fname,pat,callback)
return function()
for line in io.lines(fname) do
if line:match(pat) then callback(line) end
end
end
end
-- (* используем *)for line in co.wrap(linesLike('lines-like.lua','^loc',co.yield)) do
print('!!',line)
end
!! local co = coroutine
!! local function linesLike(fname,pat,callback)