Domanda

Ho lo stesso codice, scritto utilizzando win32com e XLRD. XLRD preforme l'algoritmo in meno di un secondo, mentre win32com richiede pochi minuti.

Questa è la win32com:

def makeDict(ws):
"""makes dict with key as header name, 
   value as tuple of column begin and column end (inclusive)"""
wsHeaders = {} # key is header name, value is column begin and end inclusive
for cnum in xrange(9, find_last_col(ws)):
    if ws.Cells(7, cnum).Value:
        wsHeaders[str(ws.Cells(7, cnum).Value)] = (cnum, find_last_col(ws))
        for cend in xrange(cnum + 1, find_last_col(ws)): #finds end column
            if ws.Cells(7, cend).Value:
                wsHeaders[str(ws.Cells(7, cnum).Value)] = (cnum, cend - 1)
                break
return wsHeaders

E il XLRD

def makeDict(ws):
"""makes dict with key as header name, 
   value as tuple of column begin and column end (inclusive)"""
wsHeaders = {} # key is header name, value is column begin and end inclusive
for cnum in xrange(8, ws.ncols):
    if ws.cell_value(6, cnum):
        wsHeaders[str(ws.cell_value(6, cnum))] = (cnum, ws.ncols)
        for cend in xrange(cnum + 1, ws.ncols):#finds end column
            if ws.cell_value(6, cend):
                wsHeaders[str(ws.cell_value(6, cnum))] = (cnum, cend - 1)
                break
return wsHeaders
È stato utile?

Soluzione

(0) hai chiesto: "Perché è così win32com molto più lento di XLRD?" ... questa domanda è un po 'come "Hai smesso di picchiare tua moglie?" --- si basa su un presupposto che non può essere vero; win32com è stato scritto in C da un programmatore brillante, ma XLRD è stato scritto in puro Python da un programmatore media. La vera differenza è che win32com deve chiamare COM che coinvolge la comunicazione tra processi e è stato scritto da tu-sai-chi, mentre XLRD sta leggendo il file di Excel direttamente. Inoltre, c'è una quarta festa nello scenario: TU. Si prega di leggere.

(1) Come ospite non ci mostrano la fonte della funzione find_last_col() che usate ripetutamente nel codice COM. Nel codice XLRD, siete felici di utilizzare lo stesso valore (ws.ncols) per tutto il tempo. Così nel codice COM, si dovrebbe chiamare find_last_col(ws) UNA VOLTA e successivamente utilizzato il risultato restituito. Aggiorna separata su come per ottenere l'equivalente di Sheet.ncols di XLRD da COM.

(2) Accesso ciascun valore di cella TWICE sta rallentando entrambi i codici. Invece di

if ws.cell_value(6, cnum):
    wsHeaders[str(ws.cell_value(6, cnum))] = (cnum, ws.ncols)

try

value = ws.cell_value(6, cnum)
if value:
    wsHeaders[str(value)] = (cnum, ws.ncols)

Nota: ci sono 2 casi di questo in ogni frammento di codice

.

(3) Non è affatto chiaro quale sia lo scopo dei tuoi cicli annidati sono, ma ci sembra essere un po 'di elaborazioni inutili, coinvolgendo recupera ridondanti da COM. Se si cura di dirci ciò che si sta cercando di ottenere, con esempi, potremmo essere in grado di aiutare a fare funzionare molto più veloce. Per lo meno, l'estrazione dei valori da COM, una volta poi la loro elaborazione in cicli annidati in Python dovrebbe essere più veloce. Quante colonne vi sono?

Aggiorna 2 Nel frattempo il piccoli elfi hanno preso al codice con il proctoscopio, e si avvicinò con il seguente script:

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

che emette questo:

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)}

Altri suggerimenti

COM richiede di parlare con un altro processo che gestisce in realtà le richieste. XLRD lavora in-process sulle strutture di dati stessi.

Il pensiero a questo proposito come stavo andando a letto la notte scorsa, e finito per usare questo. Una versione di gran lunga superiore al mio originale:

def makeDict(ws):
"""makes dict with key as header name, 
   value as tuple of column begin and column end (inclusive)"""
wsHeaders = {} # key is header name, value is column begin and end inclusive
last_col = find_last_col(ws)

for cnum in xrange(9, last_col):
    if ws.Cells(7, cnum).Value:
        value = ws.Cells(7, cnum).Value
        cstart = cnum
    if ws.Cells(7, cnum + 1).Value:
        wsHeaders[str(value)] = (cstart, cnum) #cnum is last in range
return wsHeaders
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top