def dump(xs) :
print'One:',
for x in xs : print x,
print
print'Two:',
for x in xs : print x,
print
def series(n) :
for x in range(n) : yield x
print'Range:'
dump(range(5))
print'Series:'
dump(series(5))
def dump(xsf) : # means 'x series function'print'One:',
for x in xsf() : print x,
print
print'Two:',
for x in xsf() : print x,
print
dump(lambda : range(5))
dump(lambda : series(5))
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re: [Python] Можно ли клонировать или перезапускать генерато
К>А хотелось бы, чтоб генератор был неотличим от контейнера. При том, что алгоритм генератора может быть довольно кудрявым.
Ну можно просто превратить в контейнер dump(list(series(5))) или использовать itertools.tee (но он тоже использует дополнительую память), так что твой вариант с лямбдами может быть и лучше.
Re[2]: [Python] Можно ли клонировать или перезапускать генер
Здравствуйте, FR, Вы писали: К>>А хотелось бы, чтоб генератор был неотличим от контейнера. При том, что алгоритм генератора может быть довольно кудрявым. FR>Ну можно просто превратить в контейнер dump(list(series(5))) или использовать itertools.tee (но он тоже использует дополнительую память), так что твой вариант с лямбдами может быть и лучше.
Не зная природы генератора без дополнительной памяти не обойтись...
Вот простой пример
def rnd_gen():
yield random( )
... << RSDN@Home 1.2.0 alpha rev. 721>>
Re: [Python] Можно ли клонировать или перезапускать генерато
Здравствуйте, Кодт, Вы писали:
К>А хотелось бы, чтоб генератор был неотличим от контейнера.
Да странно. Вообще-то это могли бы и в самом языке поддержать.
Достаточно, чтобы при вызове генераторной функции возвращался не сам итератор, а нечто с методом __iter__. (Тут можно вспомнить C#-овской разделение IEnumerable-IEnumerator).
Здравствуйте, eugals, Вы писали:
E>Да странно. Вообще-то это могли бы и в самом языке поддержать. E>Достаточно, чтобы при вызове генераторной функции возвращался не сам итератор, а нечто с методом __iter__. (Тут можно вспомнить C#-овской разделение IEnumerable-IEnumerator).
На самом деле, это ещё вопрос о глубине копирования (или о чистоте рук).
Если какой-то рядовой генератор является параметром замыкания, то все экземпляры "правильного" генератора его расшарят между собой, что приведёт к неадекватностям.
def squares() :
for x in range(10) :
yield x*x
@real_generator
def roots(xs) :
for x in xs :
yield sqrt(x)
if x==1 : break# чуть более затейливая логика, чтоб веселее было
s = squares
r = roots(s)
print list(r) # [0.0, 1.0]print list(r) # [2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
Кстати, а что это за супер-синтаксис? Где почитать о нём? (В мануале к 2.4 с разбегу не нашёл)
E>@real_generator
E>def foo():
E> yield 42
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[3]: [Python] Можно ли клонировать или перезапускать генер
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, eugals, Вы писали:
К>На самом деле, это ещё вопрос о глубине копирования (или о чистоте рук).
Это да, а ещё можно в генераторе заложиться на глобальную переменную, тогда вообще ой.
Понятно, что если уж использовать эту технику, то повсеместно, т.е. все без исключения генераторые функции должны быть "чистыми"
К>Кстати, а что это за супер-синтаксис? Где почитать о нём? (В мануале к 2.4 с разбегу не нашёл) К>
Здравствуйте, eugals, Вы писали:
E>Понятно, что если уж использовать эту технику, то повсеместно, т.е. все без исключения генераторые функции должны быть "чистыми"
Правда, тогда пришлось бы отказаться от generator expression-ов — у них та же проблема.
>>> x = (i for i in (1, 2, 3))
>>> x
<generator object at 0x00C48440>
>>> list(x)
[1, 2, 3]
>>> list(x)
[]
Тут уж никакой декоратор не спасет
... << RSDN@Home 1.2.0 alpha rev. 679>>
Re[5]: [Python] Можно ли клонировать или перезапускать генер
Здравствуйте, eugals, Вы писали:
E>Правда, тогда пришлось бы отказаться от generator expression-ов — у них та же проблема.
А это как раз и лечится лямбдами
>>> x = lambda : (i*i for i in (1,2,3))
>>> x
<function <lambda> at 0x00B877B0>
>>> x()
<generator object at 0x00B86AD0>
>>> list(x)
[1, 2, 3]
>>> list(x)
[1, 2, 3]
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[6]: [Python] Можно ли клонировать или перезапускать генер
Здравствуйте, eugals, Вы писали:
E>Вообще, в том что касается работы итераторами/генераторами мне больше нравится подход ruby (это вообще, видимо, самое лучшее, что есть в том языке):
Вернее так:
x = [1, 2, 3].map { |i| i * i }
puts x # puts - аналог питоновского print
puts x
А вот так через генератор:
def over_squares
for i in (1..3)
yield i * i
end
end
over_squares { |i| puts i }
over_squares { |i| puts i }
... << RSDN@Home 1.2.0 alpha rev. 679>>
Re[8]: [Python] Можно ли клонировать или перезапускать генер
Здравствуйте, eugals, Вы писали:
E>Вообще, в том что касается работы итераторами/генераторами мне больше нравится подход ruby (это вообще, видимо, самое лучшее, что есть в том языке):
Что именно больше нравится?
— Морфизмы как методы объекта-списка?
— Или то, что получается выражение с использованем HOF, вместо того, чтоб написать legacy for?
(В питоне с этим трудности — лямбда-выражение не может содержать инструкции).
Кстати, а лепо ли, что map, помимо побочных эффектов, ещё и список (из nil'ов) возвращает?
Правильнее было бы использовать each либо (для извращенцев) inject.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[9]: [Python] Можно ли клонировать или перезапускать генер
Здравствуйте, Кодт, Вы писали:
К>Что именно больше нравится? К>- Морфизмы как методы объекта-списка?
Не совсем. Само по себе это достаточно спорное достоинство, всего лишь синтаксический сахар. Вместо свободных функций в руби принято всё подряд в класс подмешивать, благо язык позволяет сделать это безопасно. >— Или то, что получается выражение с использованем HOF, вместо того, чтоб написать legacy for? К>(В питоне с этим трудности — лямбда-выражение не может содержать инструкции).
Тоже не совсем. Особых проблем с этим и в питоне нет.
Кстати, в 3.0 Гвидо вообще хотел от лямбды в пользу вложенных функций отказаться (правда сейчас, вроде, остыл)
Мне нравятся не первое и не второе по отдельности, а то, что получилось в результате их синтеза.
А в результате синтеза, итерирование чисто визаульно выглядит не как разрушающие преобразования некоего объекта "итератора".
И не как серия последовательных вызовов композиции функций над неким списком, типа такого:
print map(sqrt, map(lambda x: x * x, xrange(10)))
А как поток, с расставленными вдоль его течения фильтрами, форсунками и коллекторами:
(1..9)
.map {|x| x * x }
.map { |x| sqrt(x) }
Есть в этом какая-то внутренняя естественность и прозрачность для человеческого глаза. Мне так кажется.
К>Кстати, а лепо ли, что map, помимо побочных эффектов, ещё и список (из nil'ов) возвращает? К>Правильнее было бы использовать each либо (для извращенцев) inject.
Да. Это я уже переписал в соседней ветке.
... << RSDN@Home 1.2.0 alpha rev. 679>>
Re[8]: [Python] Можно ли клонировать или перезапускать генер
Здравствуйте, eugals, Вы писали:
E>Мне нравятся не первое и не второе по отдельности, а то, что получилось в результате их синтеза. E>А в результате синтеза, итерирование чисто визаульно выглядит не как разрушающие преобразования некоего объекта "итератора". E>И не как серия последовательных вызовов композиции функций над неким списком E>А как поток, с расставленными вдоль его течения фильтрами, форсунками и коллекторами: E>
E>(1..9)
E> .map {|x| x * x }
E> .map { |x| sqrt(x) }
E>
E>Есть в этом какая-то внутренняя естественность и прозрачность для человеческого глаза. Мне так кажется.
А в хаскеле можно любую двухместную функцию записать как инфиксный оператор Которым, безусловно, является вызов метода (слева — объект, справа — кортеж аргументов).
К>А в хаскеле можно любую двухместную функцию записать как инфиксный оператор Которым, безусловно, является вызов метода (слева — объект, справа — кортеж аргументов). К>
-- Подготовить список замен к использованию в lookup
prepareSubsts x = x
-- Удалить пустые строки, пробелы и комментарии
.$ map (filter (not.isSpace) . fst . split2 ';') .$ filter (not.null)
-- Заменить каждую строку с символом # на 9 строк, где # пробегает значения от 1 до 9
.$ concatMap (\s -> map (\d->replace '#' d s) ['2'..'9'])
-- Преобразовать список строк вида "a=b" в список для lookup
.$ map (split2 '=')
Люди, я люблю вас! Будьте бдительны!!!
Re: [Python] Можно ли клонировать или перезапускать генерато
Здравствуйте, Кодт, Вы писали:
К>А хотелось бы, чтоб генератор был неотличим от контейнера. При том, что алгоритм генератора может быть довольно кудрявым.
Лучше итераторы использовать. Да и памяти едят меньше ибо для запуска генератора нужен свой стек.
По сути генератор это dormant thread который достаточно легко трансформируется в просто thread.
По идее генератор можно презапустить м помощью send(v)
Вот интерфейс генератора из SpiderMonkey:
class Generator.<O, I, E> {
public function send(i: I) : O,
public function next() : O;
public function throw(e : E) : O,
public function close() : void
};
Насколько я помню Гвидо в Python тоже send() делал.
Re: [Python] Можно ли клонировать или перезапускать генерато
Здравствуйте, Кодт, Вы писали:
К>А хотелось бы, чтоб генератор был неотличим от контейнера. При том, что алгоритм генератора может быть довольно кудрявым.
Отсюда ограничения: функция, использующая внутри себя произвольные генераторы, клонируется неадекватно. Потому что генератор внутри хранится как объект по ссылке, и будет разделяться между всеми копиями.
Клонировать можно только функции с известными типами генераторов (for_iter), или вообще без них.