Напишем функцию, которая возвращает последовательность трёх элементов: чисел 1,2,3. Простейшее решение -- return [1,2,3]. Но мы напишем функцию, которая возвращает результат с помощью генераторов, а также имеет инициализатор в начале (строка 2). И пройдёмся по её результату для вывода на stdout (строки 19-22).
Забавы ради, иницилизатор сделаем "глючным", и он нам будет выкидывать исключение (строка 2). Но мы умные, мы исключения от этой функции ожидаем, и будем их ловить (строка 14), и в таком случае результат подразумевать пустым (строка 16).
Просто, да? Вот код:
- def generator():
- raise Exception("dieplz")
- yield 1
- yield 2
- yield 3
- try:
- print('==============================')
- try:
- print("Calling function")
- items = generator()
- print("Call succeded")
- except Exception, e:
- print("Call failed with exception: %s" % e)
- items = []
- print('==============================')
- print("Iterating over items")
- for item in items:
- print("Item: %s" % item)
- print("Iteration finished")
- except Exception, e:
- print("Failed with unhandled exception: %s" % e)
- finally:
- print("Done")
- print('==============================')
Но не тут-то было! Эта функция НЕ выполняется в момент вызова функции (на строке 12). Вместо этого на невидимой прослойке интерпретатора возвращается некий объект-генератор, который попадает в переменную items. И только попытка итерации по нему (строка 20) уже реально вызывает функцию.
И исключение, которое в функции должно происходить даже до первой "заморозки выполнения", случается не в том месте, где его ждут (на строке 20 вместо ожидаемой 12). И мы ловим unhandled exception вместо итерации по пустому анти-ошибочному списку.
>python generators.py
==============================
Calling function
Call succeded
==============================
Iterating over items
Failed with unhandled exception: dieplz
Done
==============================
==============================
Calling function
Call succeded
==============================
Iterating over items
Failed with unhandled exception: dieplz
Done
==============================
Решение проблемы простое - всегда пригонять результаты генератором в известный тип: items = list(generator()). Но это решение неудобное. А если эта функция - callback, который задаётся кем-то снаружи? А если им захочется передать не колбек, а просто экземпляр итерабельного объекта? А если этот объект ещё изменит своё состояние до цикла for, и итерация действительно должна быть только в том месте?
Не без изъянов, в общем, язычок-то.
December 17 2009, 03:07:39 UTC 2 years ago
Так что твоя проблема - в недопонимании того, что вызывая generator() ты вызваешь не тело функции, а всего лишь создаёшь генератор, т.к. функция, определённая с yield превращается в функцию-генератор )
Вот там курили:
http://www.python.org/dev/peps/pep-0
http://www.python.org/dev/peps/pep-0
December 17 2009, 04:53:10 UTC 2 years ago
January 4 2010, 18:05:22 UTC 2 years ago
p.s. а вообще, сам на Python давно поглядываю и всем его рекомендую на вопрос "какой язык учить", как универсальный язык, но сам сижу на perl по историческим причинам.
January 4 2010, 20:05:42 UTC 2 years ago
Один раз учил и практиковал когда админил/со-админил у провайдера и для себя. Всякие скрипты, парсеры, и пр.
Второй раз учил когда думал туда переползти с пхп; но, увидев тамошний "ООП", испугался и вытер из памяти чтоб не повредить своё мировоззрение %-)
January 4 2010, 22:13:04 UTC 2 years ago
в чём-то ты прав, счастье в неведении: копнув глубже, можно усомниться: ООП вообще хреновая парадигма, странно что до сих пор не сдохла, её век должен был закончиться на С++.
Инкапсулировать данные в наборы методов воздействия на них можно множеством других способов, например замыканиями (которые есть и в Perl (потому я ещё на нём), и в JS (потому я его оценил), и в Python (потому я его рекомендую)).
Вообще, предел интегральной сложности для современной вершины парадигм разработки (ООП) настанет довольно скоро, но прыгнем мы скорее всего сразу в декларативное программирование (если осилят разработку приличных оптимизаторов, осуществляющих алгоритмическую декомпозицию лучше человека), минуя эпоху lazy* и closures.
January 4 2010, 22:25:20 UTC 2 years ago
Замыкания - ок, есть в питоне красивые, есть в JS. Если JS не пошёл в массы поскольку сфера применения ограничена по факту (хотя что мешает расширить), то почему питон не идёт - непонятно. Видимо, замыкания - удел гуи и прочего интерактивного, как альтернативное решение для передачи состояния. Не вебовское точно, не скриптовое.
Декларативное ждём-с. Пока что это вещь в себе, судить не о чем. Хотя, кстати... А чё ждать? У меня с 2002 года в голове концепты и наброски как программировать на естественном языке и как это парсить и интерпретировать. Надо брать и разрабатывать. Ай, лентяй :-)
January 4 2010, 22:43:36 UTC 2 years ago
>Массовому программисту "только что из школы" оно не по силам
нет, это потому, что сейчас период массового программирования, заполняются ниши. после заполнения ниш начнётся конкуренция среди разработчиков, школота сгинет и вместе с разработчиками начнут конкурировать и средства разработки
> Если JS не пошёл в массы
пошёл: ещё немного и почти вся прикладнуха будет в браузере на стороне клиента
> почему питон не идёт - непонятно
в целом идёт, смотри хотя бы в сторону империи зла (Google), .ру просто как всегда самобытно развивается
> Видимо, замыкания - удел гуи и прочего интерактивного, как альтернативное решение для передачи состояния. Не вебовское точно, не скриптовое.
вебовое и скриптовое далеко не синонимы, а во-вторых, мы в любом случае будем вынуждены переходить на асинхронный код и каллбеки (а позже на декларативное программирование) в силу интеграции пригладнухи в сеть.
> Пока что это вещь в себе, судить не о чем
SQL давно и прочно тут, XSLT тоже, Haskel не щупал не знаю в чём там проблема, но да - это всё слишком криво, хотя главное - оптимизаторы. Декларативное должно формировать лучший (в силу машинной алгоритмической оптимизации, автоматической распределяемости на треды и асинхронные сетевые запросы), а скоро и просто единственно возможный код (в силу того, что распределяемость, автооптимизация и асинхронность станут жизненно-важной необходимостью в силу сложности решаемых задач, что вручную делать нереально).
January 4 2010, 23:13:28 UTC 2 years ago
January 4 2010, 23:37:15 UTC 2 years ago
впрочем, выступая в качестве менеджера крупного проекта, часто применяешь ООП на архитектурном(системном) уровне + спагетти на прикладом, дабы иметь возможность нанимать таджикских прикладников, ибо pretty код они не осилят. Излишне идеализирующий менеджер/архитектор почти наверняка зафакапит проект.
как всегда, контекст превыше всего
December 18 2009, 17:59:25 UTC 2 years ago
xxx: можешь сказать в чем главная ошибка
yyy: он изначально рассматривает генератор как функцию и ожидает что она сразу начнет выполняться
xxx: хм, а как надо?
yyy: вызов генератора лучше рассматривать как создание объекта
xxx: понятно, спасиб
December 18 2009, 18:42:15 UTC 2 years ago
try: items = callback()
except: items = []
for item in items:
print(item)
def fn1(): return [1,2,3]
def fn2(): yield 10
doit(fn1)
doit(fn2)
Простой, казалось бы, синтаксис у doit. Вменяемый. А вот юз-кейс подкачал. Потому что "фокус".
December 18 2009, 18:46:41 UTC 2 years ago