2014-09-01 2 views
0

Хорошо, поэтому я попытался прочитать несколько источников: One, Two, Three. Первый источник ясно указывает, что использование выражений генератора сохраняет память и ускоряет работу. Но что происходит, когда они становятся вложенными? Вот пример, и я надеюсь, что кто-то сможет помочь мне понять это.Является ли гнездование генераторов в Python лучше?

In [1]: def nested(): 
      [(ix, '-'.join(str(x) for x in hours)) for ix in table.index.get_level_values(0)] 
     %timeit nested 
Out [1]: 10000000 loops, best of 3: 33.5 ns per loop 

In [2]: def not_nested(): 
      hr = '-'.join(str(x) for x in hours) #hr = 7-8 
      [(ix, hr) for ix in table.index.get_level_values(0)] 
     %timeit not_nested 
Out [2]: 10000000 loops, best of 3: 38.7 ns per loop 

В приведенном выше примере, hours список 2 элементов длиной, в то время как количество индексов в table на уровне 0 равно 32.

Если бы я был запустить две функции в моей голове, я предположил бы, что в функции nested вторая половина кортежа ('-'.join(str(x) for x in hours) будет вызываться столько раз, сколько выполняется цикл «внешний» (ix) (то есть столько раз, сколько есть индексов в table). Однако в функции not_nested вторая половина кортежа инициализируется один раз (сохраняется в hr) и не будет запускаться каждый раз, когда выполняется вторая строка.

Во-первых, правильно ли я думаю, что так работает Python? Если я тогда, то кто-нибудь может объяснить, как время выполнения вложенной функции меньше, чем одно не вложенное?

Begin Редактировать/Решение

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

In [1]: %timeit nested() 
Out [1]: 10000 loops, best of 3: 55.5 µs per loop 

In [2]: %timeit not_nested() 
Out [2]: 100000 loops, best of 3: 4.53 µs per loop 

В конечном счете, делая среду выполнения, когда не вложена часть от выполнения при вложенной. Спасибо всем за ответ и очищение!

End Edit

+0

Вы правы. Я только что протестировал его, и для вложенной функции требуется больше времени (используются фиктивные данные). Покажите нам правильный тест (со всеми данными), или это неверно. :) – freakish

+0

Nope, @freakish. Это была ошибка, которую я сделал, поскольку ответы ниже просветлены. – Kartik

ответ

2

Вы не измеряя время, чтобы вызвать функцию, вы измеряете время, чтобы посмотреть на имя функции в текущей области.

Пробег: %timeit nested().

Что касается причин разницы во времени - заманчиво сказать «потому что второе имя длиннее, поэтому сравнение строк в поиске хэшей занимает больше времени», но я не думаю, что это действительно правильно, потому что (I думаю) вовлеченные строки будут интернированы CPython в любом случае. Конечно, я не могу заставить Python последовательно сообщать о более длительных временах поиска более длинных имен функций в моих собственных тестах.

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

+0

Я устал от '% timeit вложенных()' и '% timeit not_nested()' для получения 55,5 микросекунд и 4,53 микросекунды соответственно. Это рассеивает мой вопрос и делает его бесполезным. Я удалю его после того, как вы прочтете это. – Kartik

+0

@Kartik: Я прочитал его, спасибо. –

1

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

Более длинные клавиши занимают больше времени для создания хеша, поэтому дельта вы видите потому, что nested - это 6 букв, а not_nested - 10 букв. Попытайтесь переключить имена, и волшебным образом более медленная функция станет быстрее в соответствии с вашим тестом.Для того, чтобы вызвать функцию, вы должны вызвать ее:

%timeit nested() 
%timeit not_nested() 
+0

Да, вы говорите правильно. Это была ошибка, которую я сделал. Сейчас этот вопрос становится бесполезным. – Kartik

Смежные вопросы