Domanda Usando le dichiarazioni su entrambi i lati di un condizionale ternario python


Perché è vietato utilizzare le dichiarazioni su entrambi i lati del condizionale ternario di Python? Non riesco a vedere alcuna ovvia ragione su come alcuni dei seguenti esempi di sintassi ingenui possano essere ambigui o infranti - ma sono sicuro che ci deve essere una buona ragione per cui non è consentita!

>>> x, y = 0, 0
>>> (x += 1) if random.choice([0, 1]) else (y += 1)
        ^
SyntaxError: invalid syntax

>>> (x if random.choice([0, 1]) else y) += 1
SyntaxError: can't assign to conditional expression


>>> print 'hello world' if random.choice([0, 1]) else raise StandardError()
  File "<stdin>", line 1
    print 'hello world' if random.choice([0, 1]) else raise StandardError()
                                                          ^
SyntaxError: invalid syntax

Puoi dare un esempio in cui consentire che una dichiarazione venga usata in un ternario potrebbe essere pericolosa o mal definita?


12
2018-01-23 07:04


origine


risposte:


Le espressioni sono evalUated, le dichiarazioni sono execbuito. Questo è qualcosa di completamente diverso.

Gli sviluppatori Python hanno deciso di separare strettamente tra espressioni e dichiarazioni. Questo ti farà "fallire presto" invece di finire con un errore difficile da debugare.

In altre lingue, come C (++), puoi fare cose come

if (i=15) {...}

ma potresti anche farlo

if (i==15) {...}

Nel primo esempio, assegni 15 alla variabile ie questo nuovo valore di i viene quindi valutato dal if.

Ancora peggio sono gli operatori di incremento / decremento. Qual è la differenza tra

if (i--) {...}

e

if (--i) {...}

?

Per il primo esempio, il valore di i viene valutato, quindi viene incrementato. Per il secondo esempio, l'ordine è il contrario, quindi se i era 1 prima, il risultato è diverso.

In Python, tali cose sono proibite dalla sintassi, a causa dell'esperienza acquisita con tali concetti in altre lingue.

Non sono abbastanza sicuro che questo risponda completamente alla tua domanda, ma spero di riuscire almeno a dare qualche idea sull'approccio pitone.


7
2018-01-23 07:13



Questo non ha nulla a che fare con le espressioni condizionali1. I programmi Python sono costituiti da istruzioni. La maggior parte delle parti della maggior parte delle dichiarazioni sono espressioni. Le espressioni contengono solo altre espressioni.

y += 1 è un'asserzione e non è consentita quando è prevista un'espressione. Il condizionale ternario nel suo complesso è un'espressione, e ognuna delle 3 parti di esso sono espressioni. Non c'è più ragione per consentire (x += 1) if random.choice([0, 1]) else (y += 1) di quanto non ci sia per permettere una delle seguenti mostruosità:

x = (y += 1)
def foo(x=(x += 1)):
    print x
print [x += 1, x *= 10]

Le espressioni sono cose che possono essere valutate con un certo valore; le affermazioni sono cose che non hanno un valore. Se consenti istruzioni come "quando vero" o "quando falso" di un'espressione condizionale, perché non consentire alcuna istruzione in qualsiasi espressione? Dopotutto, complicherebbe la grammatica in un caso particolare in modo che l'espressione condizionale fosse l'unico tipo di espressione che potesse contenere un'affermazione.

x = y + pass
[return True, import sys]

Nessuno di questi ha senso. Nemmeno (x += 1) if random.choice([0, 1]) else (y += 1)perché l'intero punto delle espressioni condizionali deve essere espressioni. Quindi sarebbe più realisticamente apparire in una dichiarazione, come ad esempio:

z = (x += 1) if random.choice([0, 1]) else (y += 1)

Si potrebbe concepire la regola che il "valore" di x += 1 è il valore di x (prima o dopo aver aggiunto 1), come fa C. Ma rende la lingua notevolmente più complicata. E questo ancora non risolve il problema di:

z = pass if (import sys) else (while False: print 17)

Qual è il valore di pass? Di import sys? Di un ciclo temporale?

Per fare questo lavoro dovresti separare le "affermazioni" come una classe di cose che esiste nella grammatica di Python in "affermazioni espressioniste" e "affermazioni normali", o inventare alcune regole arbitrarie su quale sia il valore di certi tipi di affermazione siamo. Probabilmente entrambi.

Il semplice fatto è che se stai cercando di scrivere questo come una singola affermazione:

(x += 1) if random.choice([0, 1]) else (y += 1)

Quindi Python ha già la sintassi per esprimere questa idea, ed è questo:

if random.choice([0, 1]):
    x += 1
else:
    y += 1

Non c'è bisogno di introdurre le complessità nel linguaggio (e nella leggibilità) di mettere le affermazioni come componenti di espressioni solo così puoi offuscare if affermazioni scrivendole come espressioni condizionali (il cui valore è ignorato).


1 Chiamalo "condizionale ternario" se devi, ma "ternario" o "operatore ternario" è semplicemente sciocco. Che abbia 3 operandi non è certo la cosa più importante; è come chiamare + "operatore binario".


4
2018-01-23 07:43



Prima sintassi

La tua prima sintassi è davvero tradizionale if  dichiarazione, che hai provato a scrivere in una riga con condizione e prima azione invertita. È eccessivo usare i costrutti di una sola riga in questo modo, ed è brutto e illeggibile. Python non è C.

Seconda sintassi

La tua seconda sintassi non funziona perché il risultato di un'espressione condizionale di Python è un rvalueno lvalue (il collegamento parla di C e Microsoft, ma è solo un termine comune, che si verifica in ogni lingua). rvalue è un'espressione, che può verificarsi solo sul lato destro del compito. lvalue, tuttavia, può verificarsi a destra oa sinistra. quando lvalue è sulla destra, lo è valore appena usato nella valutazione di qualsiasi cosa sul lato sinistro. quando lvalue è a sinistra, è indirizzo è usato per memorizzare il valore dell'espressione del lato destro dopo la valutazione.

In Python, tutto è di riferimento, e lvalue consente il cambiamento di ciò che il riferimento punta a, ma rvalue non lo fa.

Esempio:

a = 5 # here a is lvalue
b = a + 1 # here a is rvalue and b is lvalue

Un altro esempio di rvalue-le sole espressioni sono costanti. Dal punto di vista dell'interprete, il tuo secondo tentativo sembra proprio come

42 = 42 + 1 # WHAT THE HECK!?

Perché

Quanto a perché è stato deciso di rendere l'espressione condizionale libera da dichiarazioni (whoop, sembra che abbiamo già trovato il motivo!): come PEP 308 afferma, l'espressione condizionale è stata inizialmente introdotta per l'uso anziché soggetta a errori x and y or z espressione booleana, che ha funzionato allo stesso modo a causa di corto circuito valutazione.

Se Python doveva consentire dichiarazioni come il tuo in condizionale, quindi doveva consentire, ad esempio, raise. È considerato un cattivo stile di codice Python per fare molta logica in one-liner (come ho detto sopra).

Guarda questo

result = some_long_name / some_other_name if some_other_name != 0 else raise ZeroDivisionError

All'inizio sembra un'espressione, ma poi si comporta come un'affermazione e solleva anche eccezioni! :( Tenendo presente la raccomandazione di Python di togliere righe a 79 caratteri, non si vedrebbe nemmeno il raisein, ad esempio, visualizzazione affiancata a più finestre.



1
2018-01-23 08:51



Quale versione di Python stai usando? Questa sintassi non è supportata in Python 2.4 atleast .. il seguente ha funzionato per me su python 3.3 Su un sidenote, rimuovi la parestesia:

import random
x,y=0,0
x += 1 if random.choice([0,1]) else (y +1)

-4
2018-01-23 07:10