Topic: String formatting  (Letto 247 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline Trizio

  • python unicellularis
  • *
  • Post: 40
  • Punti reputazione: 1
    • Mostra profilo
String formatting
« il: Ottobre 15, 2018, 13:42 »
Salve. Domande banali. Python 3.5.

Quando nell'espressione passo un float al type code 'd', nella stringa risultante ottengo un intero (i.e. quello che mi aspetto):

>>> '%d' % 1.0
'1'


Quando faccio la stessa cosa con format ottengo un errore:

>>> '{:d}'.format(1.0)
ValueError: Unknown format code 'd' for object of type 'float'


I type code 'f', 'e' e 'g' accettano interi, sia con l'espressione che con format:

>>> '%f' % 1
'1.000000'

>>> '{:f}'.format(1)
'1.000000'


1) Devo per forza eseguire la conversione manualmente?

>>> '{:d}'.format(int(1.0))
'1'


2) Perché? A che diavolo serve il type code 'd' se non converte una cippa lippa?

3) Perché l'espressione e format devono convivere? Retrocompatibilità? Ha un senso per python2, non per python3.

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 2.821
  • Punti reputazione: 9
    • Mostra profilo
Re:String formatting
« Risposta #1 il: Ottobre 15, 2018, 15:30 »
string.format ha dei comportamenti leggermente diversi dal vecchio %.
A te da noia che non si possa fare '{:d}'.format(1.0), a me da fastidio l'inverso, che *si possa* fare '{:f}'.format(1)...

> 1) Devo per forza eseguire la conversione manualmente?
Se vuoi puoi farlo, ma un conto è castare un float a int e poi rappresentarlo come stringa, un conto rappresentare a stringa un float specificandone la precisione. Nota che oltretutto i due sistemi seguono regole di arrotondamento differenti. Quello che probabilmente stai cercando è la seconda che ho detto, e sarebbe
>>> '{:.0f}'.format(1.6)
'2'

e come forse già hai visto, invece
>>> int(1.6)
1

che può essere (o no) quello che vuoi...

> 2) Perché? A che diavolo serve il type code 'd' se non converte una cippa lippa?
Ehm. Come vedi, a qualcosina serve. Comunque c'è sempre la documentazione, eh: https://docs.python.org/3/library/string.html#formatspec

> 3) Perché l'espressione e format devono convivere? Retrocompatibilità? Ha un senso per python2, non per python3.
Ha senso anche per python3, visto che un mucchio di codice è stato portato senza problemi proprio perché py3 conserva cose di py2.

PS: Ah, e non hai ancora incontrato le f-string, suppongo... https://docs.python.org/3/reference/lexical_analysis.html#f-strings  ;)


Offline Trizio

  • python unicellularis
  • *
  • Post: 40
  • Punti reputazione: 1
    • Mostra profilo
Re:String formatting
« Risposta #2 il: Ottobre 15, 2018, 16:10 »
A te da noia che non si possa fare '{:d}'.format(1.0), a me da fastidio l'inverso, che *si possa* fare '{:f}'.format(1)...

Perché?

> 1) Devo per forza eseguire la conversione manualmente?
Se vuoi puoi farlo, ma un conto è castare un float a int e poi rappresentarlo come stringa, un conto rappresentare a stringa un float specificandone la precisione. Nota che oltretutto i due sistemi seguono regole di arrotondamento differenti. Quello che probabilmente stai cercando è la seconda che ho detto, e sarebbe
>>> '{:.0f}'.format(1.6)
'2'

e come forse già hai visto, invece
>>> int(1.6)
1

che può essere (o no) quello che vuoi...

Non è che la cosa mi servisse davvero, ho notato solo ora l'arcano mentre ripassavo format e giocherellavo con la console.  :D
In effetti non trovo particolarmente utile l'arrotondamento verso zero... mi seccava il fatto che il comportamento cambiasse a seconda dell'approccio scelto.

> 2) Perché? A che diavolo serve il type code 'd' se non converte una cippa lippa?
Ehm. Come vedi, a qualcosina serve. Comunque c'è sempre la documentazione, eh: https://docs.python.org/3/library/string.html#formatspec

Avevo già letto. Il punto è che l'output di un intero è sempre in base 10.

> 3) Perché l'espressione e format devono convivere? Retrocompatibilità? Ha un senso per python2, non per python3.
Ha senso anche per python3, visto che un mucchio di codice è stato portato senza problemi proprio perché py3 conserva cose di py2.

Sempre restando in argomento stringhe, suppongo che print abbia sfasciato un bel po' di codice. Tanto valeva cambiare anche lo string string formatting, così da non dover costringere le persone ad imparare due approcci diversi che risolvono lo stesso problema. O no?

PS: Ah, e non hai ancora incontrato le f-string, suppongo... https://docs.python.org/3/reference/lexical_analysis.html#f-strings  ;)

Urgh. No.

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 2.821
  • Punti reputazione: 9
    • Mostra profilo
Re:String formatting
« Risposta #3 il: Ottobre 15, 2018, 17:01 »
> Perché?
E' un'asimmetria. Ovviamente capisco la ragione, ed è giusto così. Ma resta sempre un piccolo inciampo cognitivo. Non dico che non ci dormo la notte, eh.

> mi seccava il fatto che il comportamento cambiasse a seconda dell'approccio scelto.
No, non hai capito. Non cambia il comportamento, è che proprio sono due cose diverse. String.format() ha a che vedere con la *rappresentazione* di un numero, non con le operazioni di casting. Con format() tu puoi specificare la precisione della rappresentazione di un numero decimale, ovvero quanti decimali ci vuoi mettere. Certo che poi, come caso limite, se dici che vuoi "zero decimali", allora a lato pratico quello che "sembra", quello che vedi, è un intero. Ma è un intero che risulta da una scelta di precisione nella rappresentazione, *quindi* da un arrotondamento. Il comportamento di format() è lo stesso che impostare una precisione in decimal.Decimal.
D'altra parte, int() è un casting e non c'entra niente con la precisione. Fare int() *non* vuol dire "dammi una precisione di zero decimali", vuol dire "converti il tipo". Ora, int(x) significa "la parte intera di x", quindi non devi stupirti se a lato pratico tu vedi il tuo intero troncato.
Ora, quale delle due operazioni in realtà desideri, questo devi deciderlo tu:
1) "voglio rappresentare questo float come stringa, con una precisione di zero decimali, il che coincidentalmente farà sembrare un intero questo risultato di un arrotondamento".
2) "voglio castare questo float a intero (cioè troncarlo), e quindi rappresentarlo come stringa".
Tu pensi che siano la stessa cosa concettualmente, ma con due approcci diversi, e ti annoia che possano dare risultati diversi. Ma in realtà sono due cose concettualmente diverse, ed è normale che gli approcci e i risultati siano diversi.

> Avevo già letto. Il punto è che l'output di un intero è sempre in base 10.
Quindi no, non avevi letto.

>>> '{:d}'.format(14)
'14'
>>> '{:x}'.format(14)
'e'
>>> '{:o}'.format(14)
'16'
>>> '{:b}'.format(14)
'1110'


> print abbia sfasciato un bel po' di codice. Tanto valeva cambiare anche lo string string formatting...
Sono cose diverse. Print è la stessa operazione che ha cambiato implementazione e (non troppo) semantica. L'interpolazione di stringa con il vecchio % e la nuova con format sono approcci diversi per coprire (parzialmente) lo stesso problema. Tra l'altro, a lato pratico, la transizione di print si può gestire automaticamente nella maggior parte dei casi con 2to3. La formattazione di stringa mica tanto.

Offline Trizio

  • python unicellularis
  • *
  • Post: 40
  • Punti reputazione: 1
    • Mostra profilo
Re:String formatting
« Risposta #4 il: Ottobre 15, 2018, 18:03 »
> Perché?
E' un'asimmetria. Ovviamente capisco la ragione, ed è giusto così. Ma resta sempre un piccolo inciampo cognitivo. Non dico che non ci dormo la notte, eh.

In che senso è un'assimetria?

> mi seccava il fatto che il comportamento cambiasse a seconda dell'approccio scelto.
No, non hai capito. Non cambia il comportamento, è che proprio sono due cose diverse. String.format() ha a che vedere con la *rappresentazione* di un numero, non con le operazioni di casting. Con format() tu puoi specificare la precisione della rappresentazione di un numero decimale, ovvero quanti decimali ci vuoi mettere. Certo che poi, come caso limite, se dici che vuoi "zero decimali", allora a lato pratico quello che "sembra", quello che vedi, è un intero. Ma è un intero che risulta da una scelta di precisione nella rappresentazione, *quindi* da un arrotondamento. Il comportamento di format() è lo stesso che impostare una precisione in decimal.Decimal.
D'altra parte, int() è un casting e non c'entra niente con la precisione. Fare int() *non* vuol dire "dammi una precisione di zero decimali", vuol dire "converti il tipo". Ora, int(x) significa "la parte intera di x", quindi non devi stupirti se a lato pratico tu vedi il tuo intero troncato.

Ora, quale delle due operazioni in realtà desideri, questo devi deciderlo tu:
1) "voglio rappresentare questo float come stringa, con una precisione di zero decimali, il che coincidentalmente farà sembrare un intero questo risultato di un arrotondamento".
2) "voglio castare questo float a intero (cioè troncarlo), e quindi rappresentarlo come stringa".
Tu pensi che siano la stessa cosa concettualmente, ma con due approcci diversi, e ti annoia che possano dare risultati diversi. Ma in realtà sono due cose concettualmente diverse, ed è normale che gli approcci e i risultati siano diversi.

No, probabilmente mi sono spiegato male. Quando parlavo di approcci diversi mi riferivo all'espressione % e al format method. Mi secca che la stessa operazione mi ritorni un risultato in un caso e un errore nell'altro.

> Avevo già letto. Il punto è che l'output di un intero è sempre in base 10.
Quindi no, non avevi letto.

>>> '{:d}'.format(14)
'14'
>>> '{:x}'.format(14)
'e'
>>> '{:o}'.format(14)
'16'
>>> '{:b}'.format(14)
'1110'


Ma io non mi lamento di 'b', 'o' e 'x'. Mi lamento di 'd'.  L'output di un intero è sempre in base 10:

>>> 0b1
1
>>> 0o1
1
>>> 0x1
1


>>> '{}, {}, {}'.format(0b1, 0o1, 0x1)
'1, 1, 1'


Quindi ancora mi sfugge l'utilità di 'd'. A meno che in quest'ultima sessione Python non mi schiaffi di nascosto un 'd' come type code di default (perché magari è così che funziona internamente).

Ah, forse ho capito. Credo che quando si usa format Python internamente guarda il type dell'argomento e in assenza di un type code fa sì che la rappresentazione avvenga in un certo modo. Tipo, se l'argomento è una stringa, usa 's'; se l'argomento è un intero, usa 'd'. Se l'argomento è un float, usa... qualcosa di simile a 'g'. Non capisco però come funzioni con altri oggetti, tipo sequenze, complex... boh.

> print abbia sfasciato un bel po' di codice. Tanto valeva cambiare anche lo string string formatting...
Sono cose diverse. Print è la stessa operazione che ha cambiato implementazione e (non troppo) semantica. L'interpolazione di stringa con il vecchio % e la nuova con format sono approcci diversi per coprire (parzialmente) lo stesso problema. Tra l'altro, a lato pratico, la transizione di print si può gestire automaticamente nella maggior parte dei casi con 2to3. La formattazione di stringa mica tanto.

Ah. Quindi a che è servito introdurre format? Le poche cose che aggiunge non mi sembra siano così difficili da implementare da soli. Avere due strumenti diversi per fare lo stesso lavoro francamente mi sembra solo fonte di confusione. Alla fine penso ci sia gente che è abituata a usare o solo l'espressione %, o solo format; col risultato che ovviamente tutti devono sapere come funzionano entrambi. Fattibilissimo; ma se nel fare la stessa cosa uno strumento mi restituisce un risultato accettabile e l'altro un errore...
« Ultima modifica: Ottobre 15, 2018, 18:31 da Trizio »

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 2.821
  • Punti reputazione: 9
    • Mostra profilo
Re:String formatting
« Risposta #5 il: Ottobre 15, 2018, 20:40 »
Citazione
mi riferivo all'espressione % e al format method. Mi secca che la stessa operazione mi ritorni un risultato in un caso e un errore nell'altro.
Ma perché?! Ripeto: sono due framework diversi per fare formattazione di stringhe. Non devono essere compatibili. Mica li devi usare insieme. E' come dire che ti secca che una view in Django si fa in un modo e in Flask in un altro.

Citazione
Ah, forse ho capito. Credo che quando si usa format Python internamente guarda il type dell'argomento e in assenza di un type code fa sì che la rappresentazione avvenga in un certo modo. Tipo, se l'argomento è una stringa, usa 's'; se l'argomento è un intero, usa 'd'. Se l'argomento è un float, usa... qualcosa di simile a 'g'. Non capisco però come funzioni con altri oggetti, tipo sequenze, complex... boh.
Sì ma non è che ci sia da capire. Basta leggere la documentazione, c'è scritto. E sì, per i float se non specifichi il formato non usa "qualcosa di simile a g", usa proprio "g". Così è scritto.

Citazione
Ah. Quindi a che è servito introdurre format? Le poche cose che aggiunge non mi sembra siano così difficili da implementare da soli.
Sì però davvero, quando trovi tempo leggila questa benedetta documentazione. Format fa ben più di "aggiungere poche cose". Tra l'altro, Format è stato approvato con la PEP 3101 https://www.python.org/dev/peps/pep-3101, che ti consiglio anche di guardare e che ha anche dei link che rimandano ad approfondimenti. E tra l'altro, vedo adesso che la documentazione del "vecchio stile" ha un caveat all'inizio bello grosso: https://docs.python.org/3/library/stdtypes.html?highlight=sprintf#printf-style-string-formatting

Offline Trizio

  • python unicellularis
  • *
  • Post: 40
  • Punti reputazione: 1
    • Mostra profilo
Re:String formatting
« Risposta #6 il: Ottobre 16, 2018, 18:22 »
...
« Ultima modifica: Ottobre 16, 2018, 18:26 da Trizio »

Offline Trizio

  • python unicellularis
  • *
  • Post: 40
  • Punti reputazione: 1
    • Mostra profilo
Re:String formatting
« Risposta #7 il: Ottobre 16, 2018, 18:24 »
Ma perché?! Ripeto: sono due framework diversi per fare formattazione di stringhe. Non devono essere compatibili. Mica li devi usare insieme. E' come dire che ti secca che una view in Django si fa in un modo e in Flask in un altro.

Probabilmente sono io che voglio crearmi un problema che non esiste.

Sì ma non è che ci sia da capire. Basta leggere la documentazione, c'è scritto. E sì, per i float se non specifichi il formato non usa "qualcosa di simile a g", usa proprio "g". Così è scritto.

No. Nella documentazione c'è scritto "similar to 'g' (...)".

Sì però davvero, quando trovi tempo leggila questa benedetta documentazione. Format fa ben più di "aggiungere poche cose". Tra l'altro, Format è stato approvato con la PEP 3101 https://www.python.org/dev/peps/pep-3101, che ti consiglio anche di guardare e che ha anche dei link che rimandano ad approfondimenti. E tra l'altro, vedo adesso che la documentazione del "vecchio stile" ha un caveat all'inizio bello grosso: https://docs.python.org/3/library/stdtypes.html?highlight=sprintf#printf-style-string-formatting

Leggerò con più attenzione la documentazione, grazie.
« Ultima modifica: Ottobre 16, 2018, 18:25 da Trizio »