Perché il punto e virgola è consentito in questo frammento di pitone?


166

Python non garantisce l'uso di punti e virgola per terminare le istruzioni. Quindi perché questo (sotto) è permesso?

import pdb; pdb.set_trace()

1
Si noti che tale codice è palesemente solo a scopo di debug e verrebbe presumibilmente eliminato prima che sia "fatto". Uso quel frammento così come lo hai tu, così posso spostarlo facilmente.
Nick T

Lol Sono arrivato a questa domanda dallo stesso sito web: realpython.com/python-debugging-pdb
mackycheese21

Risposte:


226

Python non richiede punti e virgola per terminare le istruzioni. I punti e virgola possono essere utilizzati per delimitare le istruzioni se si desidera inserire più istruzioni sulla stessa riga.

Ora, perché è permesso? È una semplice decisione di progettazione. Non penso che Python abbia bisogno di questo punto e virgola, ma qualcuno ha pensato che sarebbe stato bello averlo e l'aveva aggiunto al linguaggio.


16
È utile per cose cometimeit a = 5; a*a
endolito,

13
Sembra utile per le istruzioni exec es. Exec ('for a in [1,2,3]: print a; print a + 1')
Phil C

76
Sono arrivato a Python con uno sfondo di C, Obj-C, Javascript, PHP. Metto spesso un terminatore (inutile); alla fine di una linea. Ma per fortuna Python mi perdona
Paolo,

36
Il punto e virgola è molto utile nella shell django o nel debugger, quindi puoi scrivere un piccolo programma su una sola riga e ripeterlo in seguito.
Bryce,

5
@endolith Cosa timeitsignifica? a = 2; a*aè inutile poiché aè ancora 2; dovrebbe esserea = 2; a *= a
Nearoo,

59

http://docs.python.org/reference/compound_stmts.html

Le dichiarazioni composte sono composte da una o più "clausole". Una clausola è composta da un'intestazione e una "suite". Le intestazioni della clausola di una particolare istruzione composta sono tutte allo stesso livello di rientro. Ogni intestazione della clausola inizia con una parola chiave identificativa univoca e termina con due punti. Una suite è un gruppo di istruzioni controllate da una clausola. Una suite può essere una o più istruzioni semplici separate da punto e virgola sulla stessa riga dell'intestazione, seguendo i due punti dell'intestazione, oppure può essere una o più istruzioni rientrate nelle righe successive . Solo quest'ultima forma di suite può contenere istruzioni composte nidificate; quanto segue è illegale, soprattutto perché non sarebbe chiaro a quale clausola se appartenesse una seguente clausola else:

if test1: if test2: print x

Si noti inoltre che il punto e virgola si lega più strettamente dei due punti in questo contesto, quindi nell'esempio seguente vengono eseguite tutte o nessuna delle istruzioni di stampa:

if x < y < z: print x; print y; print z 

riassumendo:

compound_stmt ::=  if_stmt
                   | while_stmt
                   | for_stmt
                   | try_stmt
                   | with_stmt
                   | funcdef
                   | classdef
                   | decorated
suite         ::=  stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT
statement     ::=  stmt_list NEWLINE | compound_stmt
stmt_list     ::=  simple_stmt (";" simple_stmt)* [";"]

4
Non sapevo che la priorità del punto e virgola fosse inferiore ai due punti dopo un if. Grazie!
gaborous

3
@gaborous Personalmente sento il tuo commento abbastanza ambiguo da farmi pensare che avresti voluto dire dall'altra parte. Quindi, per chiarire, vorrei piuttosto suggerire ad altri lettori di attenersi alla frase ufficiale: in quell'esempio if cond: stmt1; stmt2; stmt3, vengono eseguite tutte o nessuna delle dichiarazioni ".
RayLuo,

Sì, questo è ciò che intendevo dire, se la priorità è inferiore, il lexer non può lasciare il blocco parent (due punti) fino a quando non vengono eseguite tutte le istruzioni di punto e virgola. Non è davvero una cosa ovvia.
gaborous

38

Python usa il ;come separatore, non un terminatore. Puoi anche usarli alla fine di una riga, il che li fa sembrare un terminatore di istruzioni, ma questo è legale solo perché le istruzioni vuote sono legali in Python - una riga che contiene un punto e virgola alla fine è di due istruzioni, la seconda uno vuoto.


28
Se aggiungi due punti e virgola alla fine (o ovunque), otterrai SyntaxError. Quindi sembra che le dichiarazioni in bianco non siano del tutto legali.
Cucu,

10
Probabilmente ha la stessa logica di liste, tuple, dadi con virgole finali valide e uguale alle loro controparti ritagliate (es. [1,2,3] == [1,2,3,]) ma non possono contenere doppie virgole . Quindi in pratica Python ha un "dispositivo di rimozione del bianco finale". Che tra l'altro è chiaro da questo:stmt_list ::= simple_stmt (";" simple_stmt)* [";"]
Cucu

@Cucu Hai ragione. Inoltre, non è possibile iniziare una riga con un punto e virgola o avviare un elenco di espressioni con una virgola. Quindi è più preciso affermare che i punti e virgola e le virgole sono separatori e terminatori opzionali.
wjandrea,

29

Punto e virgola nell'interprete

Dopo aver letto le risposte, mi manca ancora un aspetto importante dell'uso del punto e virgola, forse l'unico in cui fa davvero la differenza ...

Quando si lavora in un interprete REPL (la shell interattiva di Python, IDLE, ipython) il valore dell'ultima espressione viene stampato sullo schermo e di solito questo è il comportamento previsto.

Usando un'espressione per gli effetti collaterali

Ma in alcuni casi si desidera valutare un'espressione solo per i suoi effetti collaterali, ad esempio per vedere tracciati i risultati della simulazione matplotlib.

In questi casi (probabilmente) non vuoi vedere la schermata di reprs di matplotliboggetti che a volte vengono restituiti da una chiamata a una matplotlibfunzione e, almeno in IPython, una delle possibilità che hai è quella di aggiungere un punto e virgola all'eccessivo istruzione dettagliata , ora IPython vede la riga di input composta da due espressioni, l' matplotlibinvocazione e un'istruzione null, in modo che il valore dell'espressione composta sia Nonee nulla venga stampato sullo schermo dall'interprete (l'altra possibilità è l' assegnazione , come in _ = plot(...)ma lo trovo un po 'più invadente).

Osservazione personale

IMHO, l'uso del punto e virgola per sopprimere l'output non desiderato nell'interprete è diventato più rilevante in seguito all'introduzione del notebook IPyton, che consente di salvare l'input e l'output, incluso l'output grafico, di una sessione di interprete per la documentazione e l'eventuale riutilizzo .


Vedo, grazie per averlo condiviso! Questo ha risolto esattamente il mio problema, in cui il punto e virgola può impedire la repr da matplotlib nel notebook
ipython

Questa è una funzione solo per IPython e non è un'istruzione nulla, ma solo una sintassi speciale.
wjandrea,

@wjandrea Hai ragione, è solo ipython... Ho modificato la mia risposta per riflettere la tua osservazione.
gboffi,

Questa risposta dovrebbe essere più alta, poiché penso che sia diventato il caso d'uso più comune (con la diffusione del notebook Jupyter + flusso di lavoro IPython)
Josh Friedlander

12

Come tutti gli altri hanno notato, è possibile utilizzare i punti e virgola per separare le istruzioni. Non è necessario , e non è il solito stile.

Per quanto riguarda il motivo per cui questo è utile, ad alcune persone piace mettere due o più brevi affermazioni davvero banali su una sola riga (personalmente penso che questo trasformi diverse linee banali facilmente scremate in una linea dall'aspetto complesso e rende più difficile vedere che è banale) .

Ma è quasi un requisito quando stai invocando una fodera Python dalla shell python -c '<some python code>'. Qui non puoi usare il rientro per separare le istruzioni, quindi se il tuo liner è davvero un liner doppio, dovrai usare un punto e virgola. E se vuoi usare altri argomenti nel tuo one-liner, dovrai importare sysper arrivare a sys.argv, il che richiede una importdichiarazione separata . per esempio

python -c "import sys; print ' '.join(sorted(sys.argv[1:]))" 5 2 3 1 4
1 2 3 4 5

2
È possibile utilizzare rientro e newline quando si passano i comandi pythonnella shell: basta estendere il codice tra più righe o utilizzare un ereditario. Tuttavia, ciò non riesce se si desidera che sia un "one-liner". ;)
00dani,

include i tratti per la risposta ferroviaria con-c
n611x007

6

Mi rendo conto di essere di parte come un vecchio programmatore C, ma ci sono momenti in cui le varie convenzioni di Python rendono le cose difficili da seguire. Trovo che la convenzione di trattino sia un po 'fastidiosa a volte.

A volte, la chiarezza di quando termina un'istruzione o un blocco è molto utile. Il codice C standard spesso legge qualcosa del genere:

for(i=0; i<100; i++) {
    do something here;
    do another thing here;
}

continue doing things;

dove usi gli spazi bianchi per molta chiarezza - ed è facile vedere dove finisce il ciclo.

Python ti consente di terminare con un punto e virgola (facoltativo). Come notato sopra, ciò NON significa che ci sia un'istruzione da eseguire seguita da un'istruzione 'null'. Quindi, per esempio,

print(x);
print(y);

Equivale a

print(x)
print(y)

Se ritieni che il primo abbia un'istruzione null alla fine di ogni riga, prova - come suggerito - a fare questo:

print(x);;

Emetterà un errore di sintassi.

Personalmente, trovo il punto e virgola per rendere il codice più leggibile quando hai molti annidamenti e funzioni con molti argomenti e / o arg con nomi lunghi. Quindi, a mio avviso, questo è molto più chiaro di altre scelte:

if some_boolean_is_true:
    call_function(
        long_named_arg_1,
        long_named_arg_2,
        long_named_arg_3,
        long_named_arg_4
    );

poiché, per me, ti fa sapere che l'ultimo ')' termina un 'blocco' che correva su molte linee.

Personalmente penso che ci siano molte linee guida in stile PEP, IDE che le impongono e la convinzione che esista "un solo modo Pythonic per fare le cose". Se credi in quest'ultimo, dai un'occhiata a come formattare i numeri: a partire da ora, Python supporta quattro diversi modi per farlo.

Sono sicuro che sarò infiammato da alcuni irriducibili, ma al compilatore / interprete non importa se gli argomenti hanno nomi lunghi o brevi, e - ma per la convenzione di rientro in Python - non si preoccupa degli spazi bianchi. Il problema più grande con il codice è dare chiarezza a un altro essere umano (e anche a te stesso dopo mesi di lavoro) per capire cosa sta succedendo, dove iniziano e finiscono le cose, ecc.



5

Una citazione da " When Pythons Attack "

Non terminare tutte le dichiarazioni con un punto e virgola. È tecnicamente legale farlo in Python, ma è totalmente inutile a meno che tu non stia posizionando più di un'istruzione su una singola riga (ad esempio, x = 1; y = 2; z = 3).


4
Perché no x,y,z = 1,2,3?
Anirban Nag 'tintinmj',

5
@ AnirbanNag'tintinmj 'In questo caso particolare, credo che x, y, z = 1, 2, 3sia più lento perché incorre in un inutile round trip di costruzione di una tupla e poi immediatamente la desembla. (A proposito, non credo davvero che @communistpancake stia suggerendo il x=1; y=2; z=3modello. Penso che stia semplicemente dando un esempio di come il punto e virgola è un separatore piuttosto che un terminatore.)
RayLuo

1
@AnirbanNag - perché sarebbe stato un esempio di spazzatura di una riga multiistruzione.
CZ


3

Python ti consente di usare un punto e virgola per indicare la fine di un'istruzione se includi più di un'istruzione su una riga.



2

I punti e virgola (come punti, virgole e parentesi) tendono a causare guerre di religione. Tuttavia, essi (o un simbolo simile) sono utili in qualsiasi linguaggio di programmazione per vari motivi.

  • Pratico: la capacità di mettere diversi comandi brevi che concettualmente si uniscono sulla stessa linea. Un testo del programma che assomiglia a un serpente stretto ha l'effetto opposto di ciò che si intende per newline e rientro, che evidenzia la struttura.

  • Concettuale: separazione delle preoccupazioni tra la sintassi pura (in questo caso, per una sequenza di comandi) dalla presentazione (ad es. Newline), ai vecchi tempi chiamata "bella stampa".

Osservazione: per evidenziare la struttura, il rientro potrebbe essere aumentato / sostituito da linee verticali in modo ovvio, fungendo da "righello visivo" per vedere dove inizia e termina un rientro. Colori diversi (ad es. Seguendo il codice colore per resistori) possono compensare l'affollamento.


1

È consentito perché gli autori hanno deciso di consentirlo: https://docs.python.org/2/reference/simple_stmts.html

Se passiamo alla domanda sul perché gli autori abbiano deciso di farlo, immagino che sia così perché la semicolonna è consentita come semplice terminazione delle istruzioni almeno nei seguenti linguaggi: C ++, C, C #, R, Matlab, Perl, ...

Quindi è più veloce passare all'utilizzo di Python per le persone con background in altre lingue. E non vi è alcuna perdita di generalità in tale deicison.


1

Il punto e virgola (";") è necessario solo per la separazione delle istruzioni all'interno di uno stesso blocco, come se avessimo il seguente codice C:

if(a>b)
{
largest=a;  //here largest and count are integer variables
count+=1;
}

Può essere scritto in Python in una delle due forme:

if a>b:   
    largest=a
    count=count+1

O

if a>b:    largest=a;count=count+1

Nell'esempio precedente potresti avere un numero qualsiasi di istruzioni all'interno di un ifblocco e può essere separato da ";" anziché.

Spero che niente sia così semplice come sopra spiegato.


0

Aggiungendo alla vasta conoscenza qui presente,
questa è una risposta relativa alla libreria matplotlib

import numpy as np
import matplotlib as plt
%matplotlib notebook
linear_data = np.array([1, 2, 3, 4, 5, 6, 7, 8])
quadratic_data = linear_data**2
plt.figure()
xvals = range(len(linear_data))
plt.barh(xvals, linear_data, height = 0.3, color='b')
plt.barh(xvals, quadratic_data, height = 0.3, left=linear_data, color='r')

Se non si fornisce un punto e virgola alla fine della barra (barra orizzontale), l'output è un grafico + un indirizzo di funzione. Ma se si usano i punti e virgola alla fine di entrambe le linee barh, allora mostra solo la trama e sopprime l'output per l'indirizzo della funzione.

Qualcosa del genere: confronto


3
Questo è specifico di IPython e non si applica allo standard REPL di Python.
wjandrea,

Penso che questo sia un brillante esempio in cui il modo in cui gli scrittori di lingue pensavano che stessero introducendo semplicità, potere e uniformità non è riuscito a pensare ai problemi proprio come questo.
eSurfsnake il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.