Python: s/callback/generator/
От: Roman Odaisky Украина  
Дата: 14.07.09 07:58
Оценка:
В модуле ftplib есть такая функция:
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: Перенесено из 'Декларативное программирование'
До последнего не верил в пирамиду Лебедева.
Re: Python: s/callback/generator/
От: palm mute  
Дата: 14.07.09 08:33
Оценка: 8 (1) +1
Здравствуйте, Roman Odaisky, Вы писали:

RO>В модуле ftplib есть такая функция:

RO>...
RO>Как можно передать ей такой callback, чтобы написать
RO>т. е., заставить результат работать как генератор?

afaik, в обычном Питоне это невозможно. Это возможно в Scheme(см. continuations), Lua (см. coroutines), Stackless Python (см. tasklets + channels).
Re: Python: s/callback/generator/
От: SergH Россия  
Дата: 14.07.09 09:17
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Как можно передать ей такой callback, чтобы написать


RO>for l in ftplines(ftp, "/etc/shadow"):


Скорее всего никак. Компилятор не поймёт и не оценит. Куда ему девать возвращаемое ftplines значение?
Делай что должно, и будь что будет
Re[2]: Python: s/callback/generator/
От: palm mute  
Дата: 14.07.09 10:55
Оценка:
Здравствуйте, SergH, Вы писали:

SH>Компилятор не поймёт и не оценит. Куда ему девать возвращаемое ftplines значение?

Принципиальной проблемы — куда девать — нет. У корутины может быть множество промежуточных результатов и один конечный. Проблема только в ограниченной семантике корутин в Питоне.
Re[3]: Python: s/callback/generator/
От: SergH Россия  
Дата: 14.07.09 11:05
Оценка:
Здравствуйте, palm mute, Вы писали:

PM>Принципиальной проблемы — куда девать — нет. У корутины может быть множество промежуточных результатов и один конечный. Проблема только в ограниченной семантике корутин в Питоне.


Принципиальной нет, но есть синтаксическая.

Это всё-таки не вполне полноценные корутины, насколько я понимаю. Питоновская корутина должна возвращать итератор, т.е. объект с предопределённым интерфейсом, у него потом можно вызывать функцию next, а в конце он выбросит исключение. Для возвращаемого значения тут места нет.

А yield это просто синтаксический сахар для всего этого.
Делай что должно, и будь что будет
Re: Python: s/callback/generator/
От: Mr.Cat  
Дата: 14.07.09 11:29
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:
RO>т. е., заставить результат работать как генератор?
А как в питоне с многопоточностью? Можно было бы вынести retrlines с коллбеком в один поток (он бы блокировался на ipc), а в другом сделать генератор (который бы получал от первого потока строку и разблокировал бы колллбек).
Re[2]: Python: s/callback/generator/
От: FR  
Дата: 14.07.09 12:20
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>А как в питоне с многопоточностью? Можно было бы вынести retrlines с коллбеком в один поток (он бы блокировался на ipc), а в другом сделать генератор (который бы получал от первого потока строку и разблокировал бы колллбек).


Можно, но бесполезно из-за GIL.
Re[4]: Python: s/callback/generator/
От: FR  
Дата: 14.07.09 12:23
Оценка:
Здравствуйте, SergH, Вы писали:

SH>Это всё-таки не вполне полноценные корутины, насколько я понимаю. Питоновская корутина должна возвращать итератор, т.е. объект с предопределённым интерфейсом, у него потом можно вызывать функцию next, а в конце он выбросит исключение. Для возвращаемого значения тут места нет.


Так начиная с 2.5 yield в обе стороны работает http://www.python.org/dev/peps/pep-0342/
Re[5]: Python: s/callback/generator/
От: Roman Odaisky Украина  
Дата: 14.07.09 13:46
Оценка:
Здравствуйте, FR, Вы писали:

SH>>Это всё-таки не вполне полноценные корутины, насколько я понимаю. Питоновская корутина должна возвращать итератор, т.е. объект с предопределённым интерфейсом, у него потом можно вызывать функцию next, а в конце он выбросит исключение. Для возвращаемого значения тут места нет.


FR>Так начиная с 2.5 yield в обе стороны работает http://www.python.org/dev/peps/pep-0342/


Так это поможет всё-таки переделать интерфейс на коллбэках в интерфейс на генераторах?
До последнего не верил в пирамиду Лебедева.
Re[6]: Python: s/callback/generator/
От: palm mute  
Дата: 14.07.09 13:53
Оценка: +1
Здравствуйте, Roman Odaisky, Вы писали:

FR>>Так начиная с 2.5 yield в обе стороны работает http://www.python.org/dev/peps/pep-0342/


RO>Так это поможет всё-таки переделать интерфейс на коллбэках в интерфейс на генераторах?


Нет, это всего лишь позволяет организовать двусторонний обмен сообщениями между генератором и вызывающим кодом.
Re[4]: Python: s/callback/generator/
От: palm mute  
Дата: 14.07.09 14:04
Оценка: 2 (1)
Здравствуйте, SergH, Вы писали:

SH>Это всё-таки не вполне полноценные корутины, насколько я понимаю. Питоновская корутина должна возвращать итератор, т.е. объект с предопределённым интерфейсом, у него потом можно вызывать функцию next, а в конце он выбросит исключение. Для возвращаемого значения тут места нет.

Неполноценность питоновских генераторов в другом — ограниченность контекста одной процедурой, тем хорошо раскрыта в Lua wiki.

SH>А yield это просто синтаксический сахар для всего этого.

С вашего позволения придерусь к терминологии, т.к. тут на РСДН принятно слишком вольно обращаться с термином "синтаксический сахар". О синтаксическом сахаре можно говорить в том случае, когда есть тривиальное синтаксическое преобразование, превращающее программу с сахаром в программу без сахара. Например, for-loop тривиально преобразуется в while-loop (используя __iter__, next и StopIteration). yield — примитив языка.
Re[5]: Python: s/callback/generator/
От: SergH Россия  
Дата: 14.07.09 14:50
Оценка:
Здравствуйте, palm mute, Вы писали:

PM>Неполноценность питоновских генераторов в другом — ограниченность контекста одной процедурой, тем хорошо раскрыта в Lua wiki.


Насколько я понял, это о том же.

SH>>А yield это просто синтаксический сахар для всего этого.

PM>С вашего позволения придерусь к терминологии, т.к. тут на РСДН принятно слишком вольно обращаться с термином "синтаксический сахар". О синтаксическом сахаре можно говорить в том случае, когда есть тривиальное синтаксическое преобразование, превращающее программу с сахаром в программу без сахара. Например, for-loop тривиально преобразуется в while-loop (используя __iter__, next и StopIteration). yield — примитив языка.

Согласен, неаккуратно выразился.

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

В Lua же вытащили её наружу. В результате функцию нужно явно завернуть в корутину (если я прввильно понял текст, Lua я не знаю). И поведение корутины ни с чем другими не спутаешь.

Т.е. в Питоне более удобно решен частный случай проблемы.
Делай что должно, и будь что будет
Re[3]: Python: s/callback/generator/
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 14.07.09 15:12
Оценка:
Здравствуйте, FR, Вы писали:

FR>Здравствуйте, Mr.Cat, Вы писали:


MC>>А как в питоне с многопоточностью? Можно было бы вынести retrlines с коллбеком в один поток (он бы блокировался на ipc), а в другом сделать генератор (который бы получал от первого потока строку и разблокировал бы колллбек).


FR>Можно, но бесполезно из-за GIL.


Для данной задачи GIL пофиг. Всё равно он хотел исполнять это в одной нитке, так что две которые аккуратно переключаются — будут исполнять то же самое с минимумом оверхеда.

Кстати, GIL уже не абсолют: http://code.google.com/p/unladen-swallow/
The God is real, unless declared integer.
Re: Python: s/callback/generator/
От: neFormal Россия  
Дата: 15.07.09 08:52
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Как можно передать ей такой callback, чтобы написать


можно сделать свой итератор, назвать его ftplines
...coding for chaos...
Re[2]: Python: s/callback/generator/
От: neFormal Россия  
Дата: 15.07.09 09:01
Оценка:
Здравствуйте, neFormal, Вы писали:

RO>>Как можно передать ей такой callback, чтобы написать

F>можно сделать свой итератор, назвать его ftplines

прикольный всё таки язык
class footp:
    x = ['a', 'd', 'b', 'e', 'c']
    def __init__(self):
    self.it = iter(self.x)
    
    def retrlines(self, cable):
    try:
            cable(self.it.next())
    except StopIteration, e:
        return False
    return True

class ftplines:
    def __init__(self, f):
    self.f = f
    
    def __iter__(self):
    return self
    
    def __assign(self, x):
    self.x = x
    
    def next(self):
    if self.f.retrlines(self.__assign) == False:
        raise StopIteration
    return self.x

ftp = footp()
for l in ftplines(ftp):
    print 'sup /rsdn.dynamic/ ' + l
...coding for chaos...
Re[3]: Python: s/callback/generator/
От: c-smile Канада http://terrainformatica.com
Дата: 15.07.09 21:25
Оценка: :)
Здравствуйте, neFormal, Вы писали:

Сугубо для сравнения вот функция в TIScript которая итерирует все строки в файле path удовлетворяющих template

function linesLike( path, template )
{
  var stream = Stream.openFile(path, "rt");
  if( stream )
     return function() // returning function - generator of strings matching the template
     {
       while(true)
       {
         var line = stream.readln();
         if( typeof line != #string )
            break; // EOF, exit
         if( line like template )  
            return line; // return matching line
       }
       stream.close();
     }
}


Используем например так:

for( var line in linesLike("/some/file", "ftp://*") )
   stdout << line << "\n";
Re[4]: Python: s/callback/generator/
От: FR  
Дата: 16.07.09 02:32
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Здравствуйте, neFormal, Вы писали:


CS>Сугубо для сравнения вот функция в TIScript которая итерирует все строки в файле path удовлетворяющих template


Оно примерно также и будет в питоне тоже, вопрос был в том чтобы итерировать класс который для этого не предназначен и превратить принимаемые им callback в итератор.
Re[5]: Python: s/callback/generator/
От: c-smile Канада http://terrainformatica.com
Дата: 16.07.09 03:39
Оценка:
Здравствуйте, 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);
Re[6]: Python: s/callback/generator/
От: c-smile Канада http://terrainformatica.com
Дата: 16.07.09 03:48
Оценка:
Здравствуйте, c-smile, Вы писали:

Или вообще практически в одну строку:
function linesOfResponse( cmd ) { var lines = []; 
                                  retrlines(cmd, :line: lines.push(line) ); 
                                  return lines; }

for( var line in linesOfResponse( "LIST" ) )
  stdout.printf("%s\n", line);
Re[5]: Python: s/callback/generator/
От: z00n  
Дата: 16.07.09 05:14
Оценка:
Здравствуйте, FR, Вы писали:

CS>>Сугубо для сравнения вот функция в TIScript которая итерирует все строки в файле path удовлетворяющих template


FR>Оно примерно также и будет в питоне тоже, вопрос был в том чтобы итерировать класс который для этого не предназначен и превратить принимаемые им callback в итератор.


Вот на луа с корутинами, примерно как palm mute выше писал:

-- (* lines-like.lua *)
local co = coroutine

-- (* linesLike :: str, str, callback -> thunk *)
local function linesLike(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)
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.