[Python] 0 in (False,) // 0 == False

Pietro Battiston toobaz a email.it
Ven 5 Feb 2010 15:54:44 CET


Il giorno ven, 05/02/2010 alle 14.58 +0100, Daniele Varrazzo ha scritto:
> On Fri, 05 Feb 2010 14:41:00 +0100, Pietro Battiston <toobaz a email.it>
> wrote:
> > Il giorno ven, 05/02/2010 alle 13.25 +0100, Daniele Varrazzo ha scritto:
> >> On Fri, 5 Feb 2010 09:57:44 +0100, Lawrence Oluyede
> <l.oluyede a gmail.com>
> >> wrote:
> >> > 2010/2/5 Pietro Battiston <toobaz a email.it>:
> >> >> A questo punto, la
> >> >> domanda è, a parità di duck typing, cosa abbia di comodo 0 == False,
> >> >> e
> >> >> l'unica risposta che sono in grado di formulare è "facilità di
> >> >> implementazione".
> >> > 
> >> > Non e` quella l'unica risposta, e` molto comodo avere 0, [], {}, () e
> >> > altri contenitori equivalenti a False.
> >> > Si parla di programmazione all'atto pratico, non per forza di
> >> > comodita` dell'implementatore.
> >> 
> >> Rispondo a questo msg ma solo perché non saprei a quale appendermi :P
> >> 
> >> Non confondiamo 2 cose: una è "essere falso in contesto booleano", per
> >> cui
> >> "if X:" può andare in un ramo o nell'altro a seconda del valore di
> >> X.__nonzero__(). Un'altra è il fatto che si possa fare True + False
> >> (l'algebra di boole non prevede operatori numerici tipo la somma).
> > 
> > A me veniva spontaneo identificare il lavoro su campi finiti, e in
> > particolare sugli interi modulo 2^n, ed in particolare sugli interi
> > modulo 2, con un'estensione dell'algebra di boole: per questo immaginavo
> > con "+" lo xor. Ma riconosco che può essere un viaggio mentale mio, e
> > comunque non c'entra molto col nocciolo del discorso.
> > 
> >> Un'altra
> >> ancora è il fatto che True + True faccia 2 (che volendo è un dettaglio
> >> implementativo, volendo è una convenzione che viene dal C). Bene: le
> due
> >> cose da non confondere sono 3.
> >> 
> >> 1) Il fatto che ci siano diverse cose "testabili come valori di verità"
> >> è
> >> molto comodo in python, più ancora di avere True e False (che infatti
> >> sono
> >> abbastanza recenti: python 2.3 iirc). Chiedere che if []: non debba
> >> essere
> >> possibile ma debba essere necessario fare "if bool([]):" mi sembra
> fuori
> >> questione (non così per Raffaele Salmaso, quindi non è un gusto
> >> universale... a me piace che sia così).
> > 
> > e qui ci siamo
> > 
> >> 
> >> 2) Se Python fosse puristicamente puro, forse bool non implementerebbe
> la
> >> somma. Ora la implementa semplicemente perché eredita da int, ma se
> >> anche
> >> non fosse così l'aritmetica mista (1 + true) sarebbe comunque auspicata
> >> (anche nel "mondo perfetto" evocato da Guido) per cui, o implementando
> >> __add__, o implementando __int__ e quindi lasciandosi sommare dopo una
> >> conversione in un intero, in qualche modo si sarebbe fatto. È come dire
> >> "è
> >> sensato che esista una funzione definita dai bool agli int". Se non
> >> esistesse, la gente se la scriverebbe perché farebbe comodo, quindi
> >> tanto
> >> vale uniformare il valore di di int(B) per ogni B booleano.
> > 
> > ci siamo
> > 
> >> 
> >> 3) Deciso che deve fare un numero,
> > 
> > nel senso - e solo nel senso - che deve _comportarsi come un numero_ dal
> > punto di vista del duck typing
> > 
> >> quanto devono valere int(True) e
> >> int(False)? Python usa la convenzione C, dove non ci sono bool, solo
> >> numeri, e 0 è il valore falso (quello che fa prendere il ramo else ad
> un
> >> if) e 1 è il valore vero (nel senso che !0 = 1, e !!10 = 1, non che
> >> esista
> >> una keyword "true"). È un numero sensato perché non é dipendente
> >> dall'implementazione (mentre il risultato del not booleano "~0" lo è) e
> >> perché qualunque rappresentazione numerica plausibile (interi, floating
> >> point, virgola fissa, numeri complessi...) penso si possa assumere
> >> conterrà
> >> 0 e 1 :)
> > 
> > ci siamo
> > 
> >> 
> >> Credo che il thread sia partito facendosi domande sul punto 2).
> > 
> > Credo di no: nel punto 2) ti chiedi se la somma e il casting automatico
> > a int dei booleani abbia senso, e io come te credo di sì.
> > 
> > Il punto è solo se Bool deve essere una subclass di int.
> 
> La domanda originale, come riportata anche nel titolo è: perchè "0 in
> (False,)" fa True? Questa è una diretta conseguenza di tuple.__contains__,
> che porta alla domanda "perché '0 == False' fa True?". Questo è perché si è
> desiderata l'aritmetica mista. 

no, vedi sotto

> Alessandro fa un passo ulteriore e "incolpa"
> questa proprietà al fatto che bool sublassi int. Ma il subclassing è solo
> il modo (economico) in cui si è deciso di implementare la proprietà: si
> sarebbe potuto avere aritmetica mista senza subclass, ed entrambe le
> domande nel titolo del post sarebbero ancora... domandabili.
> 
> 
> > Ripeto: in un mondo ideale, io asserterei "True + 1 == 2" _e_ "True !=
> > 1" senza timore...
> 
> A me un pò di timore fa... Se le due proprietà di sopra fossero vere:
> 
> True + 1 == 2 => True + 1 - 1 == 2 - 1 => True == 1
> 
> Quindi non puoi avere anche True != 1, a meno di non rompere il
> funzionamento degli interi.
> 

A me sembra tu stia assumendo che True sia un intero (dato che parli di
"funzionamento degli interi") per concludere che deve essere un intero.
Io ti dico che non lo vorrei nemmeno considerato come tipo numerico, ma
come un generico tipo che fa il casting ad intero(/float) in modo
sensato nelle operazioni con altri int.

Ti concedo che quanto hai scritto sopra è controintuitivo per chi è
abituato a ragionare con i bool sottoclassi di int... ma a me False == 0
sembra controintuitivo ad un livello molto più immediato; mi rendo conto
che è questione di gusti ma, con tutto il rispetto, non riesco a non
pensare che i gusti qui siano un po' condizionati da quello che offre la
casa...

Per cui onestamente da quel che dici tu non riesco a convincermi della
tua (vostra) posizione.

Per farti un esempio: ora come ora,

>>> 1 + ''
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'

OK, supponiamo che per qualsivoglia motivo a me faccia comodo che
  numero + stringa
restituisca
  numero + len(stringa)
, e quindi mi faccio le mie due classi che ereditano da int e str
rispettivamente, in cui faccio l'override di tutte le operazioni
aritmetiche che mi fanno comodo, rimpiazzando ogni argomento stringa con
len(stringa).
Bene, puoi dire che è inutile e stupido, ma non mi si "rompe" proprio
niente: sarà perfettamente normale che, se int(a) == 0 e int(b) == 1,
  a != []
ma
  [] + b = b + a

Ora, immagina che invece che subclassare io implementi direttamente la
stessa operazione in cpython direttamente in int e str... cosa cambia?!

Pietro



Maggiori informazioni sulla lista Python