2015-06-26 8 views
6

Recentemente ho dovuto completare un compito che utilizzava molte operazioni di coordinate. Pensando di risparmiare tempo e semplificare il mio codice, ho definito una classe per incapsulare il comportamento di una coppia di coordinate. La classe si presentava così:Istanza di oggetti estremamente lenta in Python 2.7

class Vector (tuple) : 
    def __init__ (self, value) : 
     tuple.__init__ (self, value) 


    def __add__ (self, other) : 
     return Vector ((self [0] + other [0], self [1] + other [1])) 

Questo mi ha permesso di scrivere codice come questo (per esempio):

def translate (pointList, displacement) : 
    return [point + displacement for point in pointList] 

Ma la mia domanda è stata terribilmente lento. Molto più lento di altri compiti. Non sono riuscito a individuare alcuna inefficienza nella mia implementazione dell'algoritmo, quindi ho fatto un semplice test per vedere quale fosse il sovraccarico della classe Vector. Mi aspettavo da qualche parte tra il 5% e il 15%.

La mia prova della classe vettoriale si presentava così:

v = Vector ((0, 0)) 
d = Vector ((1, -1)) 
loopIdx = 3000000 
while loopIdx > 0 : 
    v = v + d 
    loopIdx -= 1 
print (v) 

Questo viene eseguito (in genere) in questo tipo di tempo:

real 0m8.440s 
user 0m8.367s 
sys  0m0.016s 

Per confronto mi sono imbattuto di questo codice:

v = (0, 0) 
dX = 1 
dY = -1 
loopIdx = 3000000 
while loopIdx > 0 : 
    v = (v [0] + dX, v [1] + dY) 
    loopIdx -= 1 
print (v) 

Il tempo di esecuzione per questo codice è:

real 0m1.004s 
user 0m0.995s 
sys  0m0.006s 

Ho fatto qualcosa di gravemente sbagliato, oppure usare gli oggetti di classe in Python significa davvero che la tua applicazione impiegherà più di 8 volte il tempo di esecuzione?

+0

Probabilmente non è la classe stessa, più che la tupla è implementata direttamente in C mentre la classe non lo è. –

+1

Non una risposta alla domanda, ma: invece della classe 'Vector', potresti semplicemente usare i numeri' complessi' per rappresentare le coordinate 2D. Aggiunta, sottostringa, valore assoluto (per distanza) ecc. Inclusi.Inoltre, questo è un altro 2-3 volte più veloce rispetto all'utilizzo di tuple come nel tuo secondo approccio. –

+1

Si potrebbe considerare una classe con '__slots__' per ridurre al minimo l'impronta di memoria di ogni istanza. – jonrsharpe

risposta

1

Non è davvero una risposta su come rendere la lezione più veloce, ma più come alternativa.

Invece di sottoclassi tuple e la scrittura di tutti coloro add, sub ecc metodi di te, hai freddo basta usare Python bultin complex tipo di numero per le coordinate 2D, che ha tutte quelle operazioni già integrato, corretta e e super-veloce.

>>> %timeit vector_no_init() 
1 loops, best of 3: 1.39 s per loop 
>>> %timeit plain_tuple() 
1 loops, best of 3: 403 ms per loop 
>>> %timeit complex_nums() 
1 loops, best of 3: 171 ms per loop 

Per la rotazione, è possibile utilizzare la moltiplicazione complessa: basta moltiplicare coordinare il vostro complesso con un numero complesso che ha, in forma polare, valore assoluto 1 e una fase uguale all'angolo che si desidera ruotare di. Per ruotare di 90 gradi, è possibile moltiplicare per 1j (in senso antiorario) o -1j (in senso orario). Per tutti gli altri angoli, utilizzare il modulo cmath per la conversione da e in forma polare.

>>> c = complex(4, 2) 
>>> c * cmath.rect(1, math.radians(45)) 
(1.4142135623730954+4.242640687119285j) 

Tuttavia, vorrei suggerire non sottoclasse complex per fare rotate un metodo di quella classe, perché in questo caso si dovrà sovrascrivere tutti gli altri metodi, come add, così, altrimenti il ​​risultato di aggiunta sarà un normale numero complesso, non fornendo il metodo rotate. E questo annullerebbe tutti quei guadagni in termini di prestazioni, rendendolo altrettanto lento della tua classe Vector. Invece, è sufficiente creare una funzione rotate(complex, angle) -> complex.

+0

Grazie. Come risultato preliminare, l'uso di 'complex' per sostituire l'aritmetica grezza' tuple' (nessuna classe) produce un miglioramento delle prestazioni del 40%. –