2016-06-30 9 views
38

Dal True e False sono casi di int, vale quanto segue in Python:Esiste un uso legittimo della lista [True], lista [False] in Python?

>>> l = [0, 1, 2] 
>>> l[False] 
0 
>>> l[True] 
1 

capisco perché questo accade. Tuttavia, trovo questo comportamento un po 'inaspettato e può portare a bug difficili da debugare. Mi ha sicuramente morso un paio di volte.

Qualcuno può pensare a un uso legittimo di liste di indicizzazione con True o False?

+3

[Ecco un mucchio di esempi] (http://www.petercollingridge.co.uk/python-tricks/boolean -indices). –

+21

Utile per il golf del codice: print (('ko', 'ok') [a polku

+8

È un codice Python valido, se l'uso "legittimo" è quindi principalmente una questione di opinione. – skyking

risposta

59

In passato, alcune persone hanno utilizzato questo comportamento per produrre un povero-uomo conditional expression: essendo stato aggiunto al linguaggio in Python 2,5

['foo', 'bar'][eggs > 5] # produces 'bar' when eggs is 6 or higher, 'foo' otherwise 

Tuttavia, con un proper conditional expression, questo è molto malvista , per le ragioni che dici: fare affidamento sul fatto che i booleani siano una sottoclasse di interi è troppo "magico" e illeggibile per un manutentore.

Quindi, se non si è in codice golf (deliberatamente produrre codice molto compatto e oscura), utilizzare

'bar' if eggs > 5 else 'foo' 

invece, che ha il vantaggio che le due espressioni Questo seleziona tra sono pigramente valutata; se eggs > 5 è falso, l'espressione prima di if non viene mai eseguita.

+0

ma come funziona davvero Martin? ho provato list l = [2, 0, 1] solo per vedere cosa restituisce adn False restituisce 2 e True 0 .. –

+7

@ Ev.Kounis: 'True == 1',' False == 0', perché i booleani sono una sottoclasse di 'int'. Poiché 'eggs> 5' produce un valore booleano, ma l'indicizzazione assume il valore intero,' eggs> 5' è 'True' produce' ['foo', 'bar'] [1] ', altrimenti' ['foo', ' bar '] [0] 'viene prodotto. –

+0

La forma alternativa è ancora più chiara se l'entità che stai indicizzando è dettagliata? 'x = available_options [choice] .response_text [int (n <9)]' forse? Sicuramente sosterrei di mettere sempre quel 'int()' lì per renderlo più leggibile, anche se è un no-op per le definizioni del linguaggio. – nigel222

35

Se sei perplesso perché bool è un argomento indice valido: questo è semplicemente per coerenza con il fatto che bool è una sottoclasse di int e in Python è è un tipo numerico.

Se ti stai chiedendo perché bool è un tipo numerico, in primo luogo poi si deve capire che bool non era presente in vecchie versioni di Python e chi è abituato int s invece.

Aggiungerò un po 'di argomenti storici. Prima di tutto l'aggiunta di bool in python è brevemente descritta nel blogpost di Guido van Rossum (aka BDFL): The History of Python: The history of bool, True and False. Il tipo è stato aggiunto tramite PEP 285.

Il PEP contiene lo effettivo razionale utilizzato per queste decisioni. Citerò alcune delle parti del PEP di seguito.

4) Dovremmo cerchiamo di eliminare le operazioni non booleane su Caccio in futuro, attraverso opportuni avvertimenti, in modo che, per esempio True+1 sarebbe poi (in Python 3000) essere illegale?

=> No.

C'è una piccola ma rumorosa minoranza che preferirebbe vedere Caccio "libro di testo" che non supportano le operazioni aritmetiche a tutti, ma la maggior parte recensori d'accordo con me che Caccio dovrebbe sempre consentire operazioni aritmetiche.


6) Dovrebbe bool ereditare da int?

=> Sì.

In un mondo ideale, bool potrebbe essere meglio implementato come un tipo intero separata che sa come eseguire in modalità mista aritmetica. Tuttavia, ereditando bool dal int facilita l'attuazione enormemente (in parte dal tutto il codice C che chiama PyInt_Check() continuerà a lavorare - questo restituisce true per sottoclassi di int). Inoltre, ritengo questo è giusto in termini di sostituibilità: codice che richiede un int può essere alimentato un bool e si comporterà lo stesso 0 o 1. Il codice che richiede un bool potrebbe non funzionare quando viene assegnato un int; ad esempio, 3 è 0, ma entrambi 3 e 4 sono veri se considerati valori di verità .


Perché bool eredita da int, True+1 è valido e uguale 2, e così via. Questo è importante per la compatibilità all'indietro: poiché i confronti e così via attualmente restituiscono valori interi, non c'è il modo di dire cosa usano le applicazioni esistenti di questi valori .


A causa della compatibilità, il tipo bool manca molte proprietà che alcuni vorrebbero vedere. Ad esempio, sono consentite operazioni aritmetiche con uno o due argomenti bool, trattando False come 0 e True come 1. Inoltre, un valore bool può essere utilizzato come indice di sequenza .

Non vedo questo come un problema, e non voglio evolvere il linguaggio in questa direzione. Non credo che un'interpretazione più restrittiva di "Booleanness" da parte di renda più chiara la lingua .


Sommario:

  • Compatibilità: c'era un sacco di codice già utilizzato int s 0 e 1 per rappresentare False e True e alcuni di essi utilizzato tali valori numerici calcoli.
  • Non è stato visto come un grosso problema di avere un "non-libro di testo" bool tipo
  • Un sacco di persone della comunità Python voluto queste caratteristiche
  • BDFL detto.
4

Ci sono spesso modi migliori, ma gli indici booleani hanno i loro usi. Ho usato loro quando voglio convertire un risultato booleano a qualcosa di più leggibile:

test_result = run_test() 
log.info("The test %s." % ('Failed', 'Passed')[test_result])