(0) Вы спросили: «Почему win32com намного медленнее, чем xlrd?» ... этот вопрос немного похож на "Ты перестал бить свою жену?" --- оно основано на предположении, которое может быть неверным; win32com был написан на C блестящим программистом, но xlrd был написан на чистом Python обычным программистом. Реальное различие заключается в том, что win32com должен вызывать COM, который включает межпроцессное взаимодействие и было написано вами самим, а xlrd читает файл Excel напрямую. Более того, в сценарии есть четвертая сторона: ВЫ. Пожалуйста, продолжайте читать.
(1) Вы не показываете нам источник функции find_last_col()
, которую вы периодически используете в коде COM. В коде xlrd вы всегда рады использовать одно и то же значение (ws.ncols). Таким образом, в коде COM вы должны позвонить find_last_col(ws)
ONCE и затем использовать возвращенный результат. Обновление См. ответ на отдельный вопрос о том, как получить эквивалент Sheet.ncols
xlrd из COM.
(2) Доступ к каждому значению ячейки ДВАЖДЫ замедляет оба кода. Вместо
if ws.cell_value(6, cnum):
wsHeaders[str(ws.cell_value(6, cnum))] = (cnum, ws.ncols)
1017 * попробовать *
value = ws.cell_value(6, cnum)
if value:
wsHeaders[str(value)] = (cnum, ws.ncols)
Примечание: в каждом фрагменте кода есть 2 случая этого.
(3) Совершенно не очевидно, какова цель ваших вложенных циклов, но, похоже, существуют некоторые избыточные вычисления, включающие избыточные выборки из COM. Если вы хотите рассказать нам, чего вы пытаетесь достичь, с помощью примеров, мы могли бы помочь вам сделать это намного быстрее. По крайней мере, извлечение значений из COM один раз и последующая обработка их во вложенных циклах в Python должно быть быстрее. Сколько там столбцов?
Обновление 2 Тем временем маленькие эльфы взяли ваш код с помощью проктоскопа и придумали следующий скрипт:
tests= [
"A/B/C/D",
"A//C//",
"A//C//E",
"A///D",
"///D",
]
for test in tests:
print "\nTest:", test
row = test.split("/")
ncols = len(row)
# modelling the OP's code
# (using xlrd-style 0-relative column indexes)
d = {}
for cnum in xrange(ncols):
if row[cnum]:
k = row[cnum]
v = (cnum, ncols) #### BUG; should be ncols - 1 ("inclusive")
print "outer", cnum, k, '=>', v
d[k] = v
for cend in xrange(cnum + 1, ncols):
if row[cend]:
k = row[cnum]
v = (cnum, cend - 1)
print "inner", cnum, cend, k, '=>', v
d[k] = v
break
print d
# modelling a slightly better algorithm
d = {}
prev = None
for cnum in xrange(ncols):
key = row[cnum]
if key:
d[key] = [cnum, cnum]
prev = key
elif prev:
d[prev][1] = cnum
print d
# if tuples are really needed (can't imagine why)
for k in d:
d[k] = tuple(d[k])
print d
который выводит это:
Test: A/B/C/D
outer 0 A => (0, 4)
inner 0 1 A => (0, 0)
outer 1 B => (1, 4)
inner 1 2 B => (1, 1)
outer 2 C => (2, 4)
inner 2 3 C => (2, 2)
outer 3 D => (3, 4)
{'A': (0, 0), 'C': (2, 2), 'B': (1, 1), 'D': (3, 4)}
{'A': [0, 0], 'C': [2, 2], 'B': [1, 1], 'D': [3, 3]}
{'A': (0, 0), 'C': (2, 2), 'B': (1, 1), 'D': (3, 3)}
Test: A//C//
outer 0 A => (0, 5)
inner 0 2 A => (0, 1)
outer 2 C => (2, 5)
{'A': (0, 1), 'C': (2, 5)}
{'A': [0, 1], 'C': [2, 4]}
{'A': (0, 1), 'C': (2, 4)}
Test: A//C//E
outer 0 A => (0, 5)
inner 0 2 A => (0, 1)
outer 2 C => (2, 5)
inner 2 4 C => (2, 3)
outer 4 E => (4, 5)
{'A': (0, 1), 'C': (2, 3), 'E': (4, 5)}
{'A': [0, 1], 'C': [2, 3], 'E': [4, 4]}
{'A': (0, 1), 'C': (2, 3), 'E': (4, 4)}
Test: A///D
outer 0 A => (0, 4)
inner 0 3 A => (0, 2)
outer 3 D => (3, 4)
{'A': (0, 2), 'D': (3, 4)}
{'A': [0, 2], 'D': [3, 3]}
{'A': (0, 2), 'D': (3, 3)}
Test: ///D
outer 3 D => (3, 4)
{'D': (3, 4)}
{'D': [3, 3]}
{'D': (3, 3)}