Python: Почему понимание этого списка в 5000 раз медленнее, чем эквивалент для l oop? - PullRequest
3 голосов
/ 07 января 2020

У меня есть сценарий Python, который читает 1000 строк из файла CSV.

Почему итерация объекта csv.reader в представлении списка на 4 порядка медленнее, чем в явном эквиваленте для l oop?

Вот фрагменты кода и их время (через time.time()) на моей машине:

with open("file.csv", 'r', newline = "\n") as f:
    reader = csv.reader(f, delimiter = ",")
    data = [r for i, r in enumerate(reader) if i < 1000]

# Time: 26.459498167037964 s
with open("file.csv", 'r', newline = "\n") as f:
    reader = csv.reader(f, delimiter = ",")
    data = []
    for i, r in enumerate(reader):
        if i >= 1000:
            break
        data.append(r)

# Time: 0.005597114562988281 s

РЕДАКТИРОВАТЬ:

Согласно ответам версия для понимания списка читает весь файл и выбирает только те элементы, которые удовлетворяют условию i < 1000, в то время как явное значение l oop останавливается при достижении i == 1000.

Для будущих читателей этого вопроса самое элегантное решение было написано @decenze в комментариях:

import csv
from itertools import islice

with open("file.csv", 'r', newline = "\n") as f:
    reader = csv.reader(f, delimiter = ",")
    data = list(islice(reader, 0, 1000))

Ответы [ 2 ]

2 голосов
/ 07 января 2020

как говорил @Barmar, ваше понимание списка повторяется по всем строкам вашего csv-файла и не останавливается на индексе 1000, чтобы остановиться на индексе 1000, вы можете использовать islice :

with open("file.csv", 'r', newline = "\n") as f:
    reader = csv.reader(f, delimiter = ",")
    data = [r for r in islice(reader, 0, 1000)] 

эквивалентный код для понимания вашего списка, чтобы лучше понять, почему так долго:

with open("file.csv", 'r', newline = "\n") as f:
    reader = csv.reader(f, delimiter = ",")
    data = []
    for i, r in enumerate(reader):
        if i < 1000:
            data.append(r)
        # else iterate till the end of file
2 голосов
/ 07 января 2020

Вот ответ

В этом коде

with open("file.csv", 'r', newline = "\n") as f:
    reader = csv.reader(f, delimiter = ",")
    data = []
    for i, r in enumerate(reader):
        if i >= 1000:
            break
        data.append(r)

в области действия for область действия for прекратится, если i >= 1000

Но в этом коде нет ключевого слова break (поскольку вы использовали списковое понимание)

with open("file.csv", 'r', newline = "\n") as f:
    reader = csv.reader(f, delimiter = ",")
    data = [r for i, r in enumerate(reader) if i < 1000]

Почему это медленно? Потому что data = [r ...] не сломается, если i < 1000, но всегда будет читать, пока enumerate(reader) не закончится. Это отличается от предыдущего кода, где for область действия прервется, если i >= 1000. Но не для понимания списка

Вы можете использовать подобный код, используя raise StopIteration или другой метод, например

def LoopEnd():
    raise StopIteration()

with open("file.csv", 'r', newline = "\n") as f:
    reader = csv.reader(f, delimiter = ",")
    data = [r if i < 1000 else LoopEnd() for i, r in enumerate(reader)]
...