2016-03-11 12 views
6

Ho una base di codice Python2 che fa ampio uso di str per memorizzare dati binari non elaborati. Voglio supportare sia Python2 che Python3.Supporto per Python 2 e 3: str, byte o alternativa

Il tipo bytes (un alis di str) in Python2 e bytes in Python3 sono completamente diversi. Prendono diversi argomenti per costruire, indicizzare a diversi tipi e hanno diversi str e repr.

Qual è il modo migliore di unificare il codice per entrambe le versioni di Python, utilizzando un unico tipo per archiviare dati non elaborati?

+0

Perché non limitarsi a 'str'? È lo stesso tra le versioni, giusto? – zondo

+1

@zondo: no, non lo sono. 'str' in Python 3 è più o meno come' unicode' in 2. Non puoi andare a memorizzare i dati binari grezzi in 'str' in Python 3. –

+4

Usa il prefisso' b '..' 'in entrambi per definire letterali, e usa una libreria bridge come 'six' per gestire il resto dei casi. –

risposta

0

Non so su quali parti si desidera lavorare con i byte, io dietro quasi allways lavoro con ByteArray di, e questo è come lo faccio durante la lettura da un file

with open(file, 'rb') as imageFile: 
    f = imageFile.read() 
    b = bytearray(f) 

ho preso quella a destra fuori di un progetto su cui sto lavorando, e funziona sia in 2 che in 3. Forse qualcosa da guardare?

+1

Questo non è un modo molto efficiente per affrontare questo problema. Molti progetti riescono a usare 'str' in 2 e' bytes' in 3. –

+2

'bytearray' è mutabile, sfortunatamente. L'immutabilità è importante per me – slezica

0

Se il progetto è di piccole e semplici dimensioni, utilizzare six.

Altrimenti suggerisco di avere due codebase indipendenti: uno per Python 2 e uno per Python 3. Inizialmente può sembrare un lavoro non necessario, ma alla fine è molto più semplice da mantenere.

Come esempio di cosa potrebbe diventare il tuo progetto se decidi di supportare entrambi i pitoni in una base di codice singola, dai un'occhiata a protobuf di google. Un sacco di ramificazioni spesso controintuitive in tutto il codice, astrazioni che sono state modificate solo per consentire gli hack. E come il tuo progetto si evolverà non migliorerà: le scadenze giocano contro la qualità del codice.

Con due codebases separati si applicano semplicemente patch quasi identiche che non sono molto più impegnative rispetto a quelle che si presentano in anticipo se si desidera un codice unico. E sarà più facile migrare a Python 3 completamente una volta che il numero di utenti Python 2 del tuo pacchetto cadrà.

+0

'E probabilmente abbandonerai la versione di Python 2 tra circa un anno circa 'Come puoi essere così sicuro? Personalmente non toccherò 3.x per molti anni, se non del tutto e conosco un sacco di persone che si sentono allo stesso modo. Ci sono molte ragioni per cui uno non vuole o può usare Python 3.x. –

+0

Rimuoveremo questo dalla mia risposta. Non era destinato ad essere offensivo. Se ti senti di discutere sul motivo per cui non hai bisogno di Python 2 per un nuovo progetto, facciamolo in chat. – Kentzo

+0

Basi di codice separate per progetti di dimensioni maggiori? Questo è semplicemente irrinunciabile. –

0

Supponendo che sia necessario supportare solo Python 2.6 e successivi, è possibile utilizzare semplicemente bytes per, beh, byte. Utilizzare i valori letterali b per creare oggetti byte, ad esempio b'\x0a\x0b\x00'. Quando si lavora con i file, assicurarsi che la modalità includa un b (come in open('file.bin', 'rb')).
Attenzione però che l'iterazione e l'accesso agli elementi sono diversi. In questi casi, puoi scrivere il tuo codice per utilizzare i blocchi. Invece di b[0] == 0 (Python 3) o b[0] == b'\x00' (Python 2) scrivere b[0:1] == b'\x00'. Altre opzioni utilizzano bytearray (quando i byte sono modificabili) o le funzioni di supporto.

Le stringhe di caratteri devono essere unicode in Python 2, indipendenti dal porting di Python 3; altrimenti il ​​codice sarebbe probabilmente sbagliato quando si incontrano comunque caratteri non ASCII. L'equivalente è str in Python 3.
Utilizzare i valori letterali u per creare stringhe di caratteri (come u'Düsseldorf') e/o assicurarsi di avviare ogni file con from __future__ import unicode_literals. Dichiarare le codifiche dei file quando necessario avviando i file con # encoding: utf-8.
Utilizzare io.open per leggere le stringhe di caratteri dai file. Per il codice di rete, recuperare i byte e chiamare decode su di essi per ottenere una stringa di caratteri.

Se è necessario supportare Python 2.5 o 3.2, dai un'occhiata a six per convertire i letterali.

Aggiungi molte asserzioni per assicurarti che le funzioni che operano sulle stringhe di caratteri non ottengano i byte e viceversa. Come al solito, una buona suite di test con copertura del 100% aiuta molto.

Problemi correlati