-
Как вы думаете, имеет ли смысл использовать генератор в качестве обычной функции?
——————
Пример:
——————
——————from random import choice
data = 'I have a lot of money.'
def gen_as_func(choice=choice):
global data
while 1:
yield choice((data.upper, data.lower, data.strip, data.swapcase, data.title))()
gen = gen_as_func().next
def foo(choice=choice):
global data
return choice((data.upper, data.lower, data.strip, data.swapcase, data.title))()
for i in xrange(5):
print foo()
print gen()
Недостаток такого подхода заключен, как это часто водится, в его достоинстве:
аргументы генератор может принять только один раз, при инициализации, но ведь и не всякая функция обязательно должна принимать аргументы.
Зато такой подход просто обязан быть быстрее.
Правда я не заметил особого ускорения. :-( -
Я бы сказал, что ответ как раз зависит от того, нужна ли эта самая инициализация состояния с сохранением. Если нужна, то генератор часто удобен. Но тогда непонятно, зачем его ".next()" скрывать за вызовом функции. А если не нужно хранить состояние, то и генератор писать незачем. По скорости разницы не будет, и это выливается просто в очень странный способ делать простую вещь.
P.S. Оборачивайте код в [code]..[/code], чтобы он читался.
-
Спасибо, Иван.
Моё предположение о том, что вариант с генератором будет быстрее, основывалось на следующих выкладках(довольно туманных, честно говоря, и в основном позаимствованных из прочитанной документации):
- На каждый отдельный "чих" в Python создается объект кадра(frame), вдобавок к этому вызов функции довольно дорог, в-частности необходимо анализировать позиционные параметры и параметры по умолчанию.
- В случае с генератором ничего этого нет: всё аргументы анализируются один раз, а объект кадра, как я понимаю, просто ждет возобновления.
Должно быть эта экономия весьма крохотная :-). -
К слову говоря, функцию можно ускорить с помощью psyco, генератор - нет.
-
В случае генератора вы зато получаете потерю на lookup метода ".next" в словаре объекта генератора. Тут нельзя так прикидочно оценить, что быстрее. Надо делать изолированные тесты и мерять. А вернее, не надо :-) Питон, всё таки, не про это язык.
-
Против лишних движений как раз и направлена строка
.gen = gen_as_func().next
Создается локальная(в данном примере она одновременно и глобальная) ссылка на метод "next" генератора для прямого доступа к нему, без поиска по словарю.
Чего же боле? :-)
P.S.: мерять - не хочется, Python действительно не про это язык.
Хотя, с другой стороны, если что-то можно сделать быстрее и это "бесплатно", то... so-so-la-la, как говаривал Фридрих Ницше (шутка). -
gen = gen_as_func().nextА, не углядел.
-
Проясните для меня данный пример
Зачем тут явно определять глобальную переменную, ведь мы не изменяем ее в функции,def foo(choice=choice):
global data
а если так, то должено использоваться имя "вызывающего" пространства имен?
И второе, зачем явно передавать choice в функцию, ведь тут аналогичная ситуация. -
Не хочется никого обижать, но, на мой взгляд, разумное объяснение одно: bad coding style.
-
Простите, мне не понятно чему дается это самое разумное объяснение. По поводу "global data": когда начинал писать пример, задумывал его по другому и это имело смысл, а в итоге написал по-другому, и в таком варианте эта строка действительно не нужна.
зачем явно передавать choice в функцию
Кажется, Вы не совсем поняли: это не передача, а так называемая "заморозка" переменной в функции. В данном случае при определении функции создается локальная переменная choice со ссылкой на функцию choice модуля math, импортированную в глобальном пространстве имен. Доступ к локальным переменным всегда быстрее по сравнению с доступом к глобальным переменным. Это стандартный питоний подход. Но, признаю, здесь это лишняя мера. Просто такие вещи со временем делаются уже на автомате, и перестаешь обращать на них внимание :-)
-
- На каждый отдельный "чих" в Python создается объект кадра(frame), вдобавок к этому вызов функции довольно дорог, в-частности необходимо анализировать позиционные параметры и параметры по умолчанию.
- В случае с генератором ничего этого нет: всё аргументы анализируются один раз, а объект кадра, как я понимаю, просто ждет возобновления.
автор тут замечает "чих" как вызов функции
foo, но отчего-то не замечает "чих" как вызов функции.next. при этом у.nextкак раз есть неявный позиционный параметрself.короче, не экономьте на спичках, всеравно ваш код 90% времени будет проводить в сети или в базе, если это, конечно, прикладной код.
-
@elephantum
автор тут замечает "чих" как вызов функции foo, но отчего-то не замечает "чих" как вызов функции .next.
Код не прикладной, иначе эта экономия на спичках действительно была бы смешной. Я хотел выяснить именно идейную чистоту. А основной упор я делал на том, что создается только один объект кадра. Это крохи, да, я согласен, но если уж раскрывать суть, то максимально (насколько это в моих силах). Спасибо за поправку-уточнение.
-
А почему генератор только раз может принять данные? А как же send? : )
Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.




