Когда не самое подходящее время для использования генераторов python?



это скорее наоборот для чего можно использовать функции генератора Python?: генераторы python, выражения генератора и itertools модуль-это некоторые из моих любимых функций python в эти дни. Они особенно полезны при настройке цепочек операций для выполнения на большой куче данных-я часто использую их при обработке файлов DSV.



так когда же это не хорошее время для использования генератора, или выражения генератора, или ?




  • когда я должен предпочесть zip() over itertools.izip() или


  • range() over xrange() или


  • [x for x in foo] over (x for x in foo)?


мы используем генераторы, так что мы не назначение новых списков в память для промежуточных данных. Особенно это имеет смысл для больших наборов данных. Имеет ли смысл и для небольших наборов данных? Есть ли заметный компромисс между памятью и процессором?



мне особенно интересно, если кто-то сделал некоторые профилирования на этом, в свете открывающего глаза обсуждения представление понимания списка против карты () и фильтра (). ( alt link)

662   9  

9 ответов:

использовать список вместо генератора, когда:

1) нужно получить доступ к данным несколько раз (т. е. кэшировать результаты вместо их пересчета):

for i in outer:           # used once, okay to be a generator or return a list
    for j in inner:       # used multiple times, reusing a list is better
         ...

2) Вам нужно произвольный доступ (или любой другой доступ, кроме прямого последовательного порядка):

for i in reversed(data): ...     # generators aren't reversible

s[i], s[j] = s[j], s[i]          # generators aren't indexable

3) Вам нужно вступить строки (которые требуют двух проходов над данными):

s = ''.join(data)                # lists are faster than generators in this use case

4) Вы используете пользователей который иногда не может оптимизировать код генератора столько, сколько он может с обычными вызовами функций и манипуляциями со списком.

В общем, не используйте генератор, когда вам нужны операции со списком, такие как len(), reversed () и т. д.

также могут быть случаи, когда вам не нужна ленивая оценка (например, чтобы выполнить все вычисления заранее, чтобы вы могли освободить ресурс). В этом случае выражение списка может быть лучше.

Профиль, Профиль, Профиль.

профилирование кода-это единственный способ узнать, имеет ли то, что вы делаете, какой-либо эффект.

большинств использования xrange, генераторов, etc над статическим размером, малыми наборами данных. Только когда вы получаете большие наборы данных, это действительно имеет значение. диапазон() и xrange() в основном просто сделать код выглядеть немного более уродливый, и, ничего не теряя, и, возможно, набирает что-то.

Профиль, Профиль, Профиль.

вы никогда не должны пользу zip over izip,range over xrange, или список понимания над генератором понимания. В Python 3.0 range и xrange-как семантика и zip и izipсемантику.

список понимания на самом деле яснее, как list(frob(x) for x in foo) для тех времен вам нужен фактический список.

что касается производительности: при использовании psyco, списки могут быть довольно немного быстрее, чем Генераторы. В приведенном ниже примере списки почти на 50% быстрее при использовании psyco.полный()

import psyco
import time
import cStringIO

def time_func(func):
    """The amount of time it requires func to run"""
    start = time.clock()
    func()
    return time.clock() - start

def fizzbuzz(num):
    """That algorithm we all know and love"""
    if not num % 3 and not num % 5:
        return "%d fizz buzz" % num
    elif not num % 3:
        return "%d fizz" % num
    elif not num % 5:
        return "%d buzz" % num
    return None

def with_list(num):
    """Try getting fizzbuzz with a list comprehension and range"""
    out = cStringIO.StringIO()
    for fibby in [fizzbuzz(x) for x in range(1, num) if fizzbuzz(x)]:
        print >> out, fibby
    return out.getvalue()

def with_genx(num):
    """Try getting fizzbuzz with generator expression and xrange"""
    out = cStringIO.StringIO()
    for fibby in (fizzbuzz(x) for x in xrange(1, num) if fizzbuzz(x)):
        print >> out, fibby
    return out.getvalue()

def main():
    """
    Test speed of generator expressions versus list comprehensions,
    with and without psyco.
    """

    #our variables
    nums = [10000, 100000]
    funcs = [with_list, with_genx]

    #  try without psyco 1st
    print "without psyco"
    for num in nums:
        print "  number:", num
        for func in funcs:
            print func.__name__, time_func(lambda : func(num)), "seconds"
        print

    #  now with psyco
    print "with psyco"
    psyco.full()
    for num in nums:
        print "  number:", num
        for func in funcs:
            print func.__name__, time_func(lambda : func(num)), "seconds"
        print

if __name__ == "__main__":
    main()

результаты:

without psyco
  number: 10000
with_list 0.0519102208309 seconds
with_genx 0.0535933367509 seconds

  number: 100000
with_list 0.542204280744 seconds
with_genx 0.557837353115 seconds

with psyco
  number: 10000
with_list 0.0286369007033 seconds
with_genx 0.0513424889137 seconds

  number: 100000
with_list 0.335414877839 seconds
with_genx 0.580363490491 seconds

Как вы упомянули ," это особенно имеет смысл для больших наборов данных", я думаю, что это отвечает на ваш вопрос.

Если вы не ударяете по стенам, по производительности, вы все равно можете придерживаться списков и стандартных функций. Затем, когда вы столкнетесь с проблемами производительности коммутатора.

Как упоминалось @u0b34a0f6ae в комментариях, однако, использование генераторов в начале может облегчить вам масштабирование до больших наборов данных.

вы должны предпочесть понимание списка, если вам нужно сохранить значения вокруг для чего-то еще позже, и размер вашего набора не слишком велик.

например: вы создаете список, который вы будете перебирать несколько раз позже в вашей программе.

в какой-то степени вы можете думать о генераторах как о замене итераций (циклов) против понимания списка как типа инициализации структуры данных. Если вы хотите сохранить структуру данных, то используйте список понимания.

Что касается производительности, я не могу думать любой раз, что вы хотели бы использовать список генератор.

Я никогда не встречал ситуации, когда генераторы мешали бы тому, что вы пытаетесь сделать. Есть, однако, много случаев, когда использование генераторов не поможет вам больше, чем не использовать их.

например:

sorted(xrange(5))

не предлагает никаких улучшений по сравнению с:

sorted(range(5))

Comments

    Ничего не найдено.