sto dando gli ultimi ritocchi su una linea di circa 5000, la deduplicazione programma di backup (http://stromberg.dnsalias.org/~strombrg/backshift/) che gira su CPython 2. [ 567], CPython 3. [0123] (3.3 è ancora alpha 0), Pypy 1.7 e trunk Jython. Ho anche provato IronPython, ma era una cosa abbastanza diversa - non aveva una libreria standard, quindi nessun amore backshift. Oh, e può usare Cython per il suo ciclo più interno, o psyco - ma Pypy è più veloce di entrambi, specialmente sui sistemi a 32 bit.
In ogni caso, ho scoperto che a scrivere codice che viene eseguito altrettanto bene su 2.xe 3.x tutto quello che dovevo fare era:
1) (variabile) funziona allo stesso modo su entrambi 2.xe 3.x. print (variabile1, variabile2) no. Per 2.x, print (variabile) dice "valuta questa espressione tra parentesi e stampa il singolo risultato usando l'istruzione print". Per 3.x, print (variabile) dice "chiama la funzione di stampa su questo singolo risultato. Quindi print ('abc% d% d'% (1, 2)) funziona bene in entrambi, perché è un risultato a valore singolo, ed entrambi GROK l'operatore% per la formattazione stringa.
2) Evitare costanti ottali. Invece di scrivere 0755, scrivere (7 * 64 + 5 * 8 + 5).
3) per fare I/O binario in entrambi, ho usato il mio modulo bufsock: http://stromberg.dnsalias.org/~strombrg/bufsock.html Mi piacerebbe aprire un file e avvolgerlo con bufsock (o usare la classe rawio nel modulo). 2.x, restituirebbe una stringa di byte codificata come 8 stringhe di caratteri bit. In 3.x, questo restituirebbe un oggetto byte, che agisce in modo simile a un elenco di interi piccoli, quindi passerei l'uno o l'altro, testando con "isinstance (foo, str)" secondo necessità distinguere tra i due d questo, perché per un programma di backup, i byte sono byte - non volevo fare scherzi con le codifiche che ostacolavano il salvataggio dei dati in modo affidabile, e non tutte le codifiche andavano bene.
4) Quando si eseguono eccezioni, evitare la parola chiave "as". Invece, utilizzare EG:
try:
self.update_timestamp()
except (OSError, IOError):
dummy, utime_extra, dummy = sys.exc_info()
if utime_extra.errno == errno.ENOENT:
5) Un gruppo di moduli è stato rinominato nella transizione da 2.x a 3.x.Quindi provare l'importazione di uno dei due in un modulo altrimenti vuoto, con qualcosa come:
try:
from anydbm import *
except ImportError:
from dbm import *
... questo apparirebbe in un modulo di per sé, con un nome EG adbm.py. Quindi ogni volta che mi serviva un negozio con valore-chiave, importavo adbm invece delle due cose diverse necessarie per 2.xo 3.x direttamente. Poi avrei filtrato tutto tranne quel modulo tozzo, adbm.py - e cose del genere a cui il difensore non piaceva. L'idea era di pylint tutto il possibile, con le eccezioni alla regola "tutto ciò che è necessario pylint" in un piccolo modulo tutto da solo, un'eccezione per modulo.
6) Aiuta molto a configurare test di unità e test di sistema automatici eseguiti su 2.xe 3.xe quindi esegue frequentemente test su almeno un interprete 2.x e almeno un 3. x interprete. Eseguo spesso anche il mio codice sul mio codice, anche se solo un problema che ha verificato la conformità 2.5.x - Ho iniziato il progetto prima che pylint avesse il supporto 3.x.
7) Ho messo su un piccolo modulo "python2x3", che ha un paio di costanti e callable per rendere la vita più facile: http://stromberg.dnsalias.org/svn/python2x3/trunk/python2x3.py
8) b '' letterali non funzionano in 2.5, anche se specie di lavoro in 2. [67]. Invece di provare a eseguire il preprocesso o qualcosa del genere, ho impostato un constants_mod.py che aveva un sacco di cose che normalmente sarebbero b "letterali in 3.x, e li ho convertiti da una semplice stringa a qualsiasi tipo di" byte "è per 2 .xo 3.x. Quindi vengono convertiti una volta sull'importazione del modulo, non più e più a runtime. Se hai scelto come target 2. [67] e su, c'è forse un modo migliore, ma quando ho iniziato il progetto Pypy era compatibile solo con 2.5, e Jython lo è ancora.
9) In 2.x, gli interi lunghi hanno un suffisso L. In 3.x, tutti gli interi sono lunghi. Quindi sono andato solo evitando le lunghe costanti intere il più possibile; 2.x promuoverà un intero per il tempo necessario, quindi sembra che funzioni per la maggior parte delle cose.
10) Aiuta MOLTO ad avere un sacco di interpreti Python in giro per testare. Ho costruito 2. [567] e 3. [0123] e li ho messi in /usr/local/cpython-x.y/ per un facile test. Ho anche messo alcuni Pypy e Jython in/usr/local, ancora per un facile test. Avere uno script per automatizzare le build di CPython era piuttosto prezioso.
Credo che queste fossero tutte le contorsioni necessarie per ottenere un codebase Python altamente portatile in un progetto non banale. L'unica grande omissione nella lista che ho scritto sopra è che non sto cercando di usare oggetti unicode - è qualcos'altro qualcun altro è probabilmente meglio qualificato per commentare.
HTH
risposte a [questo] (http://stackoverflow.com/questions/5937251/writing-python-2-7-code-that-is-as-close-to-python-3-x-syntax-as -possibile) la domanda può aiutare. –
@BoraCaglayan: Sì, il titolo è quasi identico a quello di questa domanda :) Ma sfortunatamente quel collegamento riguarda le app Django (ovvero esiste una base di codice esistente e non devi rovinare l'app). La mia domanda riguarda app appena create, in cui non è necessario preoccuparsi che ad es. c'è molto codice che usa l'istruzione 'print' invece della funzione. Questo elimina molti problemi, credo. – Tadeck
@Tadeck: No, la funzione di stampa è un problema molto banale.La maggior parte dei problemi è la stessa, e molto più difficile. Non si evita realmente alcuna difficoltà di compatibilità usando Django. –