[Python] It's 1999 all over again
Daniele Varrazzo
piro a develer.com
Ven 14 Feb 2014 00:34:35 CET
On 2014-02-13 18:50, Dario Bertini wrote:
> On 02/13/2014 05:03 PM, Daniele Varrazzo wrote:
>> - sai che a[n] non è un carattere ma è un byte. La bugia dei
>> widechar
>> non regge. Neanche quella di unicode in python che però si rompe al
>> di
>> fuori del BMP (a meno che non lo compili 4 byte per carattere blah
>> blah)
>
> Forse sono pignolo, ma "la bugia dei widechar non regge" non vuol
> dire
> quasi nulla visto che:
> - non specifichi cos'è un widechar (è un codeunit a 16 bit, o un
> codepoint memorizzato in 32?)
> - non chiarisci in che modo non regge
wchar_t è compiler dependent: potrebbe essere anche 8 bit. Tanto per
essere utile.
Se fosse 16 bit, comunque ti servono 2 unità per esprimere un carattere
fuori BMP (surrogate pairs)
Se fosse 32 bit, comunque ci sono i caratteri combinanti. Non ne esci.
Cosa non regge è l'idea che se hai widechar, non mi interessa quanto
wide, comunque né accesso casuale né lunghezza siano operazioni
genericamente utili. Anche in utf32:
In [3]: s = u'\u0075\u0301'
In [4]: len(s)
Out[4]: 2
In [5]: print s
ú
> Python da questo punto di vista non ha nessun problema, con Py3.3
> l'astrazione unicode non mi sembra sia leaky e comunque mi risulta
> che
> tutte le distro linux fornissero da diversi anni solo le wide build
> di
> python di default
Non lo sapevo. Che spreco. Nessuno usa i caratteri fuori dal BMP <grin>
Non so come verificarlo ma sembra sia così:
>>> sys.getsizeof(u'aa') - sys.getsizeof(u'a')
4
> insomma: di default le cose funzionano bene da anni... anche se sono
> d'accordo che il fardello cognitivo del ricordarsi di "fallire
> graziosamente" sulle narrow build fosse un deal breaker
>
>> - tipicamente l'i/o non richiede encoding/decoding
>
> Questo vuol dire che se i dati che leggi non sono codificati
> correttamente te ne accorgi proprio nel mezzo dell'elaborazione
Anche in python. Tutto funziona finché non arriva un accento e le cose
si rompono. Magari si rompono in I/O, mentre tutto quello che occorreva
era leggere una stringa da un database e scriverla su una pagina web:
per un programma scritto negli ultimi 10 anni ci sono buone chance che
entrambi siano utf8 e la codifica/decodifica non era necessaria: un
accento sarebbe arrivato indenne a destinazione, anche se Python non
l'avrebbe visto come codepoint singolo.
Il problema sono i dati legacy. Go credo non ne voglia avere a che
fare, e ne approfitta per fare pulizia. Se scrivi un programma oggi da
zero sarà bene che faccia tutto con unicode/utf8. Il problema delle
codifiche 8 bit è un problema che hanno i linguaggi colla, e Go ha
deciso di semplificare su questo punto e guardare al presente/futuro
invece che al passato. Anche ora, con tutte le interfacce che gestisco
(database, web, email, file...) non uso praticamente nessun encoding che
non sia utf8. Se proprio c'è un input latin1 ok, ci sarà un decoder
sull'interfaccia che lo converte: non cambia rispetto a Python.
> penso sarebbe stato meglio fare di len("whatever") un compile error
> in
> Go, e fornire una funzione size() allo scopo... size si presta di
> meno
> ad essere fraintesa come "lunghezza di un testo"
se uno non sa che cosa sta facendo, a livello di usare una stringa
senza sapere se sono codepoint o una codifica, non vedo la necessità di
venirgli incontro. Meglio faccia un altro lavoro. Altrimenti rischia di
centrare male la stringa in cinese nello schermo.
Se per questo vorrei una macchina del tempo per dare una martellata
sulle dita di chi ha implementato str.encode() e unicode.decode(),
perpretando sempre di più l'idea che str e unicode siano
intercambiabili. Ho bestemmiato i miei santi migliori dietro alle
librerie che chiamano x.decode() qualunque cosa sia x, e siccome va bene
agli americani va bene a tutti. O meglio magari funziona nella shell ma
si rompe in crontab perchè una variabile d'ambiente è diversa [1]. Dare
ad unicode l'interfaccia non di una lista ma di un iterabile avrebbe
fatto notare che len(unicode) non è un'operazione poi così utile - e se
proprio ti serve fai len(list(u)). Invece che ha fatto in python3? Ha
azzoppato bytes rimuovendo l'operatore %, quindi tutto *deve* essere
[de]codificato. A questo punto ecco il bastone, lì ci sono i cuccioli di
foca... Ok fine rant :)
>> È un linguaggio opinionato
>
> Anche Python è un linguaggio opinionato: solo perchè a te non
> piacciono
> i bytes literals (così mi sembra), non vuol dire che "paghi sempre
> l'overhead necessario" :P
Perché non mi dovrebbero piacere i byte literal? :)
E sì, paghi overhead in codifica (input), elaborazione (4 volte la
memoria e quindi il tempo per processarla) e decodifica (output) anche
dove non sarebbe stato necessario: è un fatto che non vedo come si possa
negare. Usare unicode ovunque mi va benissimo: è giusto ed è il presente
e il futuro. È la scelta di rappresentarlo internamente come array di
codepoint che crea delle strozzature. Go non ha queste chicane, il che
lo rende più efficiente sull'I/O di qualunque magia possa fare Python.
Penso gli dia più questo che il fatto di essere compilato.
-- Daniele
[1] ok, questo è un problema diverso, ma deriva dal fatto che in python
tutti gli encoding hanno la stessa importanza, che è una panzana
colossale visto che solo uno gestisce il dominio completo, mentre gli
altri esplodono su diversi sottoinsiemi.
piro a bagheera:~$ python -c 'print u"\u20ac"'
€
piro a bagheera:~$ LC_CTYPE=C python -c 'print u"\u20ac"'
Traceback (most recent call last):
File "<string>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac'
in position 0: ordinal not in range(128)
Cosa vorrei da un linguaggio moderno? Che se chiedo di scrivere
dell'unicode in un file i dati, grazie, per favore, convertili
nell'unico encoding che può gestire tutto il dominio unicode, no, non
voglio fare una partita alla roulette degli encoding. Se in quel file
strano e curioso voglio scriverci in LATIN15 ti passerò dei byte
codificati da me. Sì esistono terminali che non gestiscono utf8. Sì,
sono io il coglione se ti chiedo di stamparci sopra €, non è colpa tua:
un risultato indeterminato va bene. Ma ti prego, non crashare alle 3 di
mattina per un print.
Maggiori informazioni sulla lista
Python