2012-08-16 6 views
18

Supponiamo di avere una multilinea in Python che solleva un'eccezione.Quale riga viene scelta per essere segnalata nell'eccezione

In che modo Python decide su quale riga generare l'eccezione?

Esempi: (Nota: ho potuto usato barre rovesciate \ dopo ogni riga)

(1 
+0/0 
+3) 

Thows un'eccezione linea 3 (un'eccezione ZeroDivisionError, a +3)).

(1 
+ 
0/0 
) 

genera un'eccezione sulla linea 3.

(0/0 
+ 
1) 

genera un'eccezione sulla linea 2.

Questa domanda è stato ispirato da this example, e @Godman pointed out che le eccezioni non solo si verificano sull'ultima riga (come avevo pensato in precedenza).

+0

Sai, mi stavo chiedendo la stessa cosa quando ho commentato l'altra domanda. –

+0

In questo caso potrebbe essere stato un altro motivo molto localizzato (ad esempio, potrebbe esserci una differenza tra il file .py e il file .pyc). –

+7

Di solito, è l'ultima riga. Nel caso in cui il codice sorgente e il codice effettivamente in esecuzione non siano sincronizzati, potrebbe essere una linea qualsiasi. Puoi usare 'dis.dis()' per vedere i numeri di riga associati ad ogni istruzione bytecode. –

risposta

1

L'eccezione punterà linea * contenente uno:

  1. L'ultimo operatore (se i letterali precedenti/operatori causato l'eccezione).

  2. L'ultimo letterale (altrimenti, l'ultimo letterale/operatore ha causato l'eccezione).

.

Tuttavia, se questo non è il comportamento che si vede, si può essere causata dalle discrepanze in uno dei tuoi py file (sorgente) e sia il suo corrispondente (compilato) file di pyc, o il codice in esecuzione (in memoria). Il seguente è un esempio illustrativo.

  • Supponiamo E.py contiene:

    def z(): 
        0/0 
    
  • Dalla riga di comando python, import E (questo verrà compilato E.py in byte-code: E.pyc, e mette in memoria).

  • chiamata E.z(), che produrrà un'eccezione, sulla linea 2 a z, visualizzando la linea 0/0 - nessuna sorpresa qui.

  • Torna al file sorgente E.py, inserisci due righe nella parte superiore e al secondo inserisci la stringa "oh dear, oh dear".

  • Torna alla riga di comando di python e chiama E.z() una seconda volta.

  • L'eccezione (riga 2, in z) ora visualizza "oh dear, oh dear".

* Aggiornamento: Non ho un punto di riferimento per questo, si prega di commento uno se vi imbattete in uno. In precedenza avevo pensato che fosse semplicemente l'ultima riga!

+0

Non importa se i file '.py' e' .pyc' non sono sincronizzati o no. La cosa importante è se il file '.py' è sincronizzato con il codice effettivamente in esecuzione (che è in memoria). –

+0

Grazie @SvenMarnach, non mi ero reso conto che questo era in memoria –

4

Fondamentalmente, non penso che tutti stiano pensando alle giuste linee. Non esiste l'ultima riga qui. L'eccezione viene sollevata dall'interprete quando riceve un'espressione completamente. Secondo la grammatica di Python: http://docs.python.org/reference/grammar.html, l'espressione non è completa fino a quando non si preme una parentesi di chiusura ')'. Joran Beasley ha fornito una breve spiegazione per lo stesso nei commenti contro la domanda stessa.

Si può fare 3 cose fanno giudicare la correttezza di questa, senza scavare molto in profondità nella grammatica: -

  1. scrivere questo codice in Python:

    a = (1 + 2 + 0/0 + 4 + 5)

Ciò solleva anche ZeroDivionError.

  1. scrivere questo codice in Python:

    a = (1 + 2 + 0/0 + 4 + 5 # e premere enter

Questo ti dà una sintassi non valida poiché l'espressione non è completa e non può essere analizzata dall'interprete PS: Questo è uguale al codice menzionato nella domanda

  1. scrivere questo codice in Python:

a = (1
+2
+0/0
+4
+5)

Alla fine, l'espressione non viene completata fino a quando non si preme la parentesi di chiusura. Quindi, puoi continuare ad aggiungere altre sotto-espressioni al suo interno senza ottenere alcuna eccezione. Quindi, fondamentalmente, l'interprete non vede tutto questo come numeri di linea; aspetta fino a quando tutte le espressioni (comprese le sotto-espressioni) sono state completate. E, è un flusso di controllo di programmazione appropriato per l'interpete.

PS: perdona la mia formattazione della risposta.

Nuovo edit: -

@ Hayden: Ho pensato che sarebbe stato facile spiegare le sfumature da non scavare troppo in profondità nella grammatica. Ma, per riferimento, sto solo copiando il codice dall'URL: http://nedbatchelder.com/blog/200804/the_structure_of_pyc_files.html

Passi da eseguire: - 1. Scrivere il codice richiesto nella domanda in un file temp.py e salvarlo, quindi, importare temp in un altro file o nell'interprete. Questo creerà temp.pyc 2. Ora, copia e incolla il codice completo nell'URL sopraindicato in byteCodeDetails.py ed esegui il file nel prompt dei comandi come: python byteCodeDetails.py temp.pyc. La show_file funzione verrà chiamata qui e darà il seguente output: -

03f30d0a magia
moddate 458c2e50 (Ven 17 Ago 23:54:05 2012) Codice
argcount 0
nlocals 0 stacksize 3 bandiere codice 0040
640600640200640200151764030017640400175a000064050053 5
LOAD_CONST 6 (3)
3 LOAD_CONST 2 (0)
6 LOAD_CONST 2 (0)
9 BINARY_DIVIDE
10 BINARY_ADD
11 LOAD_CONST 3 (4)
14 BINARY_ADD
15 LOAD_CONST 4 (5)
18 BINARY_ADD
19 store_name 0 (a)
22 LOAD_CONST 5 (nessuna)
25 RETURN_VALUE
const
Nessuno
nomi ('A',)
varnames()
freevars()
cellvars()
nome del file 'C: \ Users \ Python \ temp1.py'

nome ''
firstlineno 5
lnotab


Quindi, come si può notare che: -

  1. Citazione dal collegamento menzionato sopra: Nell'output disassemblato, i numeri più a sinistra (1, 2, 3) sono i numeri di riga nel file di origine originale e i numeri successivi (0, 3, 6, 9 , ...) sono i byte di offset dell'istruzione. Analogamente, per il tuo codice, il numero più a sinistra è solo 5, che è il numero di riga, e le colonne a destra rappresentano i mnemonici (che devono essere letti dall'interprete) tradotti dal compilatore per il tuo codice. le espressioni sono formate e la loro formazione viene superata dal valore dei numeri di riga nel codice compilato.
  2. firstlineno punta a 5.

Ora, basta fare un leggero cambiamento nel vostro codice iniziale nel file temp.py: -

a = (1
+2
+0/0
+ 4 +
5)

Ora, esegui ancora una volta i due passaggi precedenti. Quello che segue è l'output: -

magia 03f30d0a
moddate 0f8e2e50 (sab 18 agosto 00:01:43 2012)
codice
argcount 0
nlocals 0
stacksize 3

bandiere 0040
codice 640600640200640200151764030017640400175a000064050053 0 LOAD_CONST 6 (3)
3 LOAD_CONST 2 (0)
6 LOAD_CONST 2 (0)
9 BINARY_DIVIDE
10 BINARY_ADD
11 LOAD_CONST 3 (4)
14 BINARY_ADD

5 15 LOAD_CONST 4 (5)
18 BINARY_ADD
19 STORE_NAME 0 (a)
22 LOAD_CONST 5 (Nessuno)
25 RETURN_VALUE
consts
Nessuno
nomi ('A',)
varnames()
freevars()
cellvars()
nome 'C: \ Users \ Python \ temp1.py'
nome ''
firstlineno 4

lnotab 0f01

Bene, ora y ou può chiaramente vedere 2 cose: -

  1. Il codice byte è composto da 2 linee illustrate nella riga accanto a 'codice 640600640200640200151764030017640400175a000064050053', con il prefisso '4' e '5'. Questo dimostra che il compilatore ha analizzato il file .py e convertito il codice in temp.py in 2 righe di codice che verranno eseguite dall'interprete.noti che qui il contenuto della linea 4 vengono eseguite dall'interprete non importa l'espressione è completo o meno
  2. Il valore di modifiche firstlineno a 4 invece di 5

Il punto di questa lunga discussione è che, ovunque il codice byte indichi all'interprete che è qui che inizia una linea e le istruzioni corrispondenti che devono essere eseguite per questa linea, l'interprete esegue quella riga e le istruzioni corrispondenti scritte accanto ad essa.

Il codice nella domanda mostra firstlineno come 5, è per questo che si riceve un errore nella riga 5. Speriamo che questo aiuti ora.

+0

Hai ragione, in un certo senso la "linea" può rimanere ininterrotta da parentesi. Non credo che questo cambi nulla "fondamentalmente", ma mi è piaciuto il gioco di parole :) –

+0

@ Hayden: Non sono sicuro che tu sia d'accordo con la risposta o no – GodMan

+0

Non sono d'accordo, in quanto ** è ** un concetto di ultimo linea (di un'espressione) anche nel caso in cui ti preoccupi: * Se l'espressione è scritta usando parentesi la "ultima riga" è semplicemente quella contenente la finale ')'. * ** Errori di sintassi ** sembrano mostra la fina l linea come altre eccezioni ... –

Problemi correlati