2010-02-24 14 views
5

Esiste un linguaggio comune per evitare inutili fetta copia per casi come questo:Evitando inutili fetta copia in Python

>>> a = bytearray(b'hello') 
>>> b = bytearray(b'goodbye, cruel world.') 
>>> a.extend(b[14:20]) 
>>> a 
bytearray(b'hello world') 

Mi sembra che ci sia una copia inutile succede quando si crea la fetta b[14:20]. Piuttosto che creare una nuova sezione in memoria per dare a extend voglio dire "usa solo questo intervallo dell'oggetto corrente".

Alcuni metodi vi aiuterà fuori con i parametri fetta, ad esempio count:

>>> a = bytearray(1000000)  # a million zero bytes 
>>> a[0:900000].count(b'\x00') # expensive temporary slice 
900000 
>>> a.count(b'\x00', 0, 900000) # helpful start and end parameters 
900000 

ma molti, come extend nel mio primo esempio, non hanno questa caratteristica.

Mi rendo conto che per molte applicazioni quello di cui sto parlando sarebbe una micro-ottimizzazione, quindi prima che qualcuno chieda - sì, ho profilato la mia domanda, ed è qualcosa che vale la pena preoccupare per il mio caso.

Ho una "soluzione" di seguito, ma le idee migliori sono le benvenute.

risposta

5

Creazione di un oggetto buffer evita di copiare la fetta, ma per brevi fette è più efficiente di fare solo la copia:

>>> a.extend(buffer(b, 14, 6)) 
>>> a 
bytearray(b'hello world') 

Qui c'è solo una copia in memoria, ma il costo di creazione del buffer oggetto più che cancella il risparmio. Dovrebbe essere meglio per fette più grandi però. Non sono sicuro di quanto sia grande la fetta per questo metodo per essere più efficiente nel complesso.

Si noti che per Python 3 (e facoltativamente in Python 2.7) avresti bisogno di un oggetto memoryview invece:

>>> a.extend(memoryview(b)[14:20]) 
+0

il buffer è una buona scelta per gli oggetti che supportano l'interfaccia del buffer. Di solito non vale l'involucro speciale per i casi piccoli (a meno che la maggior parte dei casi d'uso siano piccoli) perché il 50% in più di una piccola quantità è ancora una piccola quantità –

2

itertools ha islice. islice non ha un metodo di conteggio, quindi è utile in altri casi in cui si desidera evitare di copiare la sezione. Come hai sottolineato, il conteggio ha comunque un meccanismo per questo

>>> from itertools import islice 
>>> a = bytearray(1000000) 
>>> sum(1 for x in islice(a,0,900000) if x==0) 
900000 
>>> len(filter(b'\x00'.__eq__,islice(a,0,900000))) 
900000 

>>> a=bytearray(b"hello") 
>>> b = bytearray(b'goodbye, cruel world.') 
>>> a.extend(islice(b,14,20)) 
>>> a 
bytearray(b'hello world') 
+0

'islice' è una buona alternativa. Ho appena fatto alcuni test rapidi e sembra veloce come 'buffer' quando usato con' extend', tuttavia sono entrambi * molto * più lenti di un semplice slice, anche per mezzo milione di elementi ... –