Накладные расходы на цикл по итерируемому классу

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

Я не смог найти удовлетворительного объяснения этой темы в Google, поэтому решил проверить их самостоятельно, используя эти два простых скрипта: func_iter.pyи class_iter.py

Вот func_iter.py:

#!/usr/bin/env python

import time  

x = 0
def create_generator(num):
    mylist = range(num)
    for i in mylist:
        yield i

t = time.time()
gen = create_generator(100000)

for i in gen:
    x = x + i

print "%.3f" % (time.time() - t)

А вот class_iter.py:

#!/usr/bin/env python

import time

x = 0

class Generator(object):

    def __init__(self, num):
        self.start = 0
        self.end = num

    def __iter__(self):
        return self

    def next(self):
        if self.start == self.end:
            raise StopIteration
        else:
            self.start = self.start + 1
            return self.start

t = time.time()
gen = Generator(100000)

for i in gen:
    x = x + i

print "%.3f" % (time.time() - t)

Затем я запускал каждый из них 10 раз, используя это в bash (для class_iter. py, например):

for i in {1..10}; do ./class_iter.py; done

А вот среднее время работы для каждого из них:

class_iter.py: 0.0864
func_iter.py: 0.0307

Теперь мои вопросы:

  1. Правильны ли мои методы? Правомерно ли мое сравнение?
  2. Если да, то почему такая большая разница? Почему class_iter.pyвыполнялся почти в три раза дольше, чем func_iter.py?
  3. Если нет, то как я могу улучшить свои методы или предложить лучшее сравнение?

РЕДАКТИРОВАТЬ: Как предложил Дакав, я также попытался запустить func_iter.py, используя xrangeвместо range. Это уменьшает его среднее время работы до 0,0263 секунды.

7
задан martineau 25 November 2019 в 16:23
поделиться