Domanda

Esistono strumenti di analisi statica per Python , ma i controlli del tempo di compilazione tendono a essere diametralmente opposti al binding run-time filosofia che Python abbraccia. È possibile avvolgere l'interprete Python standard con uno strumento di analisi statica per imporre un po 'di " usa rigorosi vincoli simili a " ma non vediamo l'adozione diffusa di una cosa del genere.

C'è qualcosa in Python che rende " usa rigoroso " comportamento non necessario o particolarmente indesiderabile?

In alternativa, è l'uso "rigoroso" comportamento non necessario in Perl, nonostante la sua diffusa adozione?

Nota: per " necessario " Intendo "praticamente necessario", non strettamente necessario. Ovviamente puoi scrivere Perl senza " usa rigoroso " ma (da quello che ho visto) la maggior parte dei programmatori Perl lo usano .

Nota: il wrapper di interprete Python non deve richiedere " usa rigorosi vincoli di tipo `` - potresti usare uno pseudo-pragma simile a " usa rigoroso " che sarebbe ignorato dall'interprete normale. Non sto parlando di aggiungere una funzionalità a livello di lingua.


Aggiornamento: spiegazione di cosa " usa rigoroso " fa in Perl per commenti. (Il collegamento ai documenti ufficiali è nel primo paragrafo.)

Il " usa rigoroso " la direttiva ha tre componenti distinte, solo due delle quali sono davvero interessanti:

  • usa rigidi parametri: controlla staticamente l'utilizzo variabile con ambito lessicale nel programma. (Tieni presente che, in Python, esiste fondamentalmente solo l'ambito globale e locale ). Molte linter Python verificano questo genere di cose. Dal momento che è l'unica analisi statica che possono fare, le linter assumono che tu usi un semplice scoping lessicale e ti avvertono di cose che sembrano sbagliate in quel senso fino a quando non dici loro di tacere; cioè.

    FOO = 12
    foo += 3
    

    Se non stai facendo nulla di fantasia con i tuoi spazi dei nomi, questo può essere utile per verificare errori di battitura.

  • usa riferimenti rigidi: impedisce la dereferenziazione simbolica dello spazio dei nomi. L'analogo più vicino a Python sta usando locals () e globals () per fare il legame simbolico e la ricerca di identificatori.

  • usa sottotitoli rigorosi: nessun vero analogo in Python.

È stato utile?

Soluzione

"la filosofia di associazione runtime che Python abbraccia ... fa" usare rigorosamente " comportamento non necessario [e] soprattutto indesiderabile "

Riepilogo abbastanza buono. Grazie.

Questo è essenzialmente. Gli strumenti di analisi statica non aiutano abbastanza Python da essere utili.


Modifica

" Sto chiedendo di introspetterci sul perché non ne abbiamo bisogno e, di conseguenza, perché i programmatori Perl pensano di averne bisogno. "

Il motivo è proprio il motivo che hai già indicato. Non ne abbiamo bisogno perché non aiuta. Chiaramente, non ti piace quella risposta, ma non c'è molto altro da dire. Il controllo del tempo di compilazione o pre-compilazione semplicemente non aiuta.

Tuttavia, poiché hai dedicato del tempo a porre nuovamente la domanda, fornirò ulteriori prove per la risposta che hai già fornito.

Scrivo Java quasi quanto scrivo Python. Il controllo statico del tipo di Java non impedisce alcun problema logico; non facilita il rispetto dei requisiti di prestazione; non aiuta a soddisfare i casi d'uso. Non riduce nemmeno il volume dei test unitari.

Mentre il controllo del tipo statico rileva occasionalmente l'uso improprio di un metodo, lo si scopre altrettanto rapidamente in Python. In Python lo trovi al momento del test unitario perché non funzionerà. Nota: non sto dicendo che si trovano tipi sbagliati con molti test unitari intelligenti, sto dicendo che la maggior parte dei problemi di tipo sbagliato si trovano attraverso eccezioni non gestite in cui la cosa semplicemente non andrà abbastanza lontano per arrivare a testare asserzioni.

Il motivo per cui i Pythonistas non perdono tempo nel controllo statico è semplice. Non ne abbiamo bisogno. Non offre alcun valore. È un livello di analisi che non ha alcun vantaggio economico. Non mi rende più in grado di risolvere i problemi reali che le persone reali hanno con i loro dati reali.

Guarda le domande più popolari su SO Python che sono legate al linguaggio (non al dominio o alla libreria problematica).

C'è qualche differenza tra " foo è Nessuno " e " foo == Nessuno " ;? - == vs. è . Nessun controllo statico può essere d'aiuto in questo. Inoltre, vedi C'è una differenza tra `==` e ` si trova in Python?

Cosa fanno ** (doppia stella) e * (stella) per parametri? - * x fornisce un elenco, ** x fornisce un dizionario. Se non lo sai, il tuo programma muore immediatamente quando provi a fare qualcosa di inappropriato per quei tipi. " Cosa succede se il tuo programma non fa mai nulla di "inappropriato" " ;. Quindi il tuo programma funziona. 'ha detto Nuff.

Come posso rappresentare un 'Enum' in Python? - questo è un motivo per un tipo di dominio limitato. Una classe con valori a livello di classe fa praticamente quel lavoro. " Cosa succede se qualcuno modifica il compito " ;. Facile da costruire. Sostituisci __set__ per sollevare un'eccezione. Sì, il controllo statico potrebbe individuare questo. No, in pratica non accade che qualcuno si confonda su una costante enum e una variabile; e quando lo fanno, è facile da individuare in fase di esecuzione. " Cosa succede se la logica non viene mai eseguita " ;. Bene, questo è un design scadente e un test dell'unità insufficiente. Lanciare un errore del compilatore e inserire una logica sbagliata che non è mai stata testata non è meglio di ciò che accade in un linguaggio dinamico quando non viene mai testato.

Espressioni del generatore vs. Comprensione dell'elenco - il controllo statico non aiuta a risolvere questa domanda.

Perché 1 +++ 2 = 3? - statico il controllo non lo individuerebbe. 1 +++ 2 in C è perfettamente legale nonostante tutto il controllo del compilatore. Non è la stessa cosa in Python come in C, ma altrettanto legale. E altrettanto confuso.

Elenco delle modifiche agli elenchi riflesse in modo imprevisto negli elenchi secondari - - Questo è del tutto concettuale. Anche il controllo statico non può aiutare a risolvere questo problema. Anche l'equivalente Java si compila e si comporta male.

Altri suggerimenti

Beh, non sono un programmatore di Python, ma direi che la risposta è 'SÌ'.

Qualsiasi linguaggio dinamico che ti consente di creare una variabile con qualsiasi nome in qualsiasi momento, potrebbe usare un pragma 'rigoroso'.

Vars rigorosi (una delle opzioni per strict in Perl, 'usa strict' li attiva tutti in una volta) in Perl richiede che tutte le variabili vengano dichiarate prima di essere utilizzate. Ciò significa che questo codice:

my $strict_is_good = 'foo';
$strict_iS_good .= 'COMPILE TIME FATAL ERROR';

Genera un errore irreversibile al momento della compilazione.

Non so come fare in modo che Python rifiuti questo codice al momento della compilazione:

strict_is_good = 'foo';
strict_iS_good += 'RUN TIME FATAL ERROR';

Otterrai un'eccezione di runtime che strict_iS_good non è definito. Ma solo quando viene eseguito il codice. Se la tua suite di test non ha una copertura del 100%, puoi spedire facilmente questo errore.

Ogni volta che lavoro in una lingua che non ha questo comportamento (ad esempio PHP), mi innervosisco. Non sono una dattilografa perfetta. Un errore di battitura semplice, ma difficile da individuare, può causare il fallimento del codice in modi che potrebbero essere difficili da rintracciare.

Quindi, per ribadire, Python potrebbe usare un pragma 'rigoroso' per attivare i controlli del tempo di compilazione per le cose che possono essere verificate al momento della compilazione. Non riesco a pensare ad altri controlli da aggiungere, ma un programmatore Python migliore probabilmente potrebbe pensare ad alcuni.

Nota Mi concentro sull'effetto pragmatico dei rigidi vars in Perl, e sto esaminando alcuni dei dettagli. Se vuoi davvero conoscere tutti i dettagli vedi il perldoc per rigoroso .

Aggiornamento: risposte ad alcuni commenti

Jason Baker : pedine statiche come il pilastro sono utili. Ma rappresentano un ulteriore passo che può essere e spesso viene saltato. La creazione di alcuni controlli di base nel compilatore garantisce che questi controlli vengano eseguiti in modo coerente. Se questi controlli sono controllabili da un pragma, anche l'obiezione relativa al costo dei controlli diventa controversa.

popcnt : so che Python genererà un'eccezione di runtime. Ho detto altrettanto. Sostengo il controllo del tempo di compilazione ove possibile. Rileggi il post.

mpeters : nessuna analisi computerizzata del codice può trovare tutti gli errori - questo equivale a risolvere il problema di arresto. Peggio ancora, per trovare errori di battitura nei compiti, il compilatore dovrebbe conoscere le tue intenzioni e trovare luoghi in cui le tue intenzioni differiscono dal tuo codice. Questo è chiaramente impossibile.

Tuttavia ciò non significa che non si debba fare alcun controllo. Se ci sono classi di problemi facili da rilevare, allora ha senso intrappolarle.

Non ho abbastanza familiarità con Pylint e Pychecker per dire quali classi di errori colpiranno. Come ho detto, sono molto inesperto con Python.

Questi programmi di analisi statica sono utili. Tuttavia, credo che, a meno che non duplicino le capacità del compilatore, il compilatore sarà sempre in grado di "conoscere" più sul programma di qualsiasi controllo statico. Sembra inutile non approfittarne per ridurre gli errori ove possibile.

Aggiornamento 2:

cdleary - In teoria, sono d'accordo con te, un analizzatore statico può fare qualsiasi validazione che il compilatore può fare. E nel caso di Python, dovrebbe essere sufficiente.

Tuttavia, se il tuo compilatore è abbastanza complesso (specialmente se hai molti pragmi che cambiano il modo in cui si verifica la compilazione, o se come Perl, puoi eseguire il codice al momento della compilazione), allora l'analizzatore statico deve avvicinarsi alla complessità del compilatore / interprete per fare l'analisi.

Heh, tutto questo parlare di compilatori complessi e di codice in esecuzione al momento della compilazione mostra il mio background Perl.

La mia comprensione è che Python non ha pragmi e non può eseguire codice arbitrario in fase di compilazione. Quindi, a meno che non mi sbagli o non vengano aggiunte queste funzionalità, dovrebbe essere sufficiente un parser relativamente semplice nell'analizzatore statico. Sarebbe sicuramente utile forzare questi controlli ad ogni esecuzione. Certo, il modo in cui lo farei è con un pragma.

Dopo aver aggiunto i pragmi al mix, hai iniziato una discesa scivolosa e la complessità del tuo analizzatore deve crescere in proporzione alla potenza e alla flessibilità che fornisci nei tuoi pragmi. Se non stai attento, puoi finire come Perl e quindi "solo Python può analizzare Python", " un futuro che non vorrei vedere.

Forse un'opzione da riga di comando sarebbe un modo migliore per aggiungere un'analisi statica forzata;)

(Non intendo in alcun modo contestare le capacità di Python quando dico che non può andare a vuoto con un comportamento in fase di compilazione come il Perl. Ho la sensazione che questa sia una decisione di progettazione attentamente considerata e posso vedere la saggezza in L'estrema flessibilità di Perl al momento della compilazione è, IMHO, una grande forza e una terribile debolezza del linguaggio; vedo anche la saggezza in questo approccio.)

Python ha qualcosa che può cambiare la sintassi dello script:

from __future__ import print_function

e varie altre funzionalità future che hanno implicazioni sulla sintassi. È solo che la sintassi di Python è stata più rigorosa, più stabile e più ben definita rispetto al Perl storico; il tipo di cose che & # 8216; ref rigidi & # 8217; e & # 8216; sottotitoli rigorosi & # 8217; il divieto non è mai esistito in Python.

& # 8216; rigidi parametri & # 8217; è principalmente inteso a fermare i riferimenti digitati e i miei errori dalla creazione di globi accidentali (beh, variabili di pacchetto in termini di Perl). Ciò non può accadere in Python in quanto le assegnazioni nude sono predefinite per la dichiarazione locale e simboli nudi non assegnati comportano un'eccezione.

(Esiste ancora il caso in cui gli utenti provano accidentalmente a scrivere su un globale senza dichiararlo con un'istruzione & # 8216; global & # 8217; causando un errore locale accidentale o, più spesso, UnboundLocalError. deve essere appreso abbastanza rapidamente, ma è un caso discutibile in cui il dovere di dichiarare la propria gente del posto potrebbe aiutare. Sebbene pochi programmatori esperti di Python accetterebbero l'onere della leggibilità.)

Le altre modifiche alla lingua e alla libreria che non comportano la sintassi vengono gestite attraverso il sistema warnings .

Penso che ci sia un po 'di confusione in quanto cosa " usa rigoroso " sì, dai commenti che vedo. Non attiva i controlli del tipo di tempo di compilazione (per essere come Java). In tal senso, i programmatori di Perl sono in accordo con i programmatori di Python. Come dice S.Lott sopra, questi tipi di controlli non proteggono dai bug logici, non riducono il numero di unit test che devi scrivere e non siamo anche grandi fan della programmazione bondage.

Ecco un elenco di ciò che " usa rigoroso " fa:

  1. L'uso di riferimenti simbolici è un errore di runtime. Questo ti impedisce di fare il matto (ma a volte cose utili come)

    $ var = 'foo';

    $ foo = 'bar';

    print $$ var; # questo conterrebbe il contenuto di $ foo se non eseguito sotto rigoroso

  2. L'uso di variabili non dichiarate è un errore di runtime (ciò significa che è necessario utilizzare " my " ;, " our " o " local " per dichiarare l'ambito della propria variabile prima di utilizzarla.

  3. Tutte le password sono considerate errori di sintassi in fase di compilazione. Le parole nude sono parole che non sono state dichiarate come simboli o subroutine. Ciò serve principalmente a mettere fuori legge qualcosa che è stato storicamente fatto ma che si ritiene sia stato un errore.

Python non ha un vero ambito lessicale, quindi i rigidi rigidi non sarebbero molto sensati. Non ha riferimenti simbolici AFAIK, quindi non ha bisogno di riferimenti rigidi. Non ha parole semplici, quindi non ha bisogno di rigidi parametri.

Ad essere sincero, mi manca solo lo scoping lessicale. Le altre due considererei le verruche in Perl.

Questa risposta originale è corretta, ma forse non spiega la situazione in senso pratico.

  

Esistono strumenti di analisi statica per Python, ma i controlli del tempo di compilazione tendono ad essere diametralmente opposti alla filosofia di associazione runtime che Python abbraccia.

Ciò che "usa rigoroso" fornisce in Perl è la capacità di assicurare che un errore di ortografia o il nome della variabile viene (di solito) catturato al momento della compilazione. Questo migliora il codice affidabilità e accelera lo sviluppo. Ma per rendere utile una cosa del genere, devi dichiarare le variabili. E lo stile Python sembra scoraggiarlo.

Quindi in Python, non si scopre mai una variabile scritta male fino a quando non si nota in run-time che l'assegnazione che pensavi di aver fatto non è stata effettuata o che un L'espressione sembra risolversi in un valore imprevisto. La cattura di tali errori può essere richiede molto tempo, soprattutto quando i programmi diventano grandi e le persone sono costrette a mantenere codice sviluppato da altri.

Java e C / C ++ fanno un passo avanti, con il controllo del tipo. La motivazione è pratica, piuttosto che filosofico. Come è possibile rilevare il maggior numero possibile di errori il più presto possibile ed essere sicuri di eliminarli tutti prima di rilasciare il codice in produzione? Ogni lingua sembra prendere una strategia particolare e correre con essa, in base a ciò che essi pensare è importante. In una lingua come Perl, dove l'associazione runtime non è supportata, ha senso approfittare dell '"uso rigoroso" per facilitare lo sviluppo.

Considero il 'use strict' in Perl più come un pragma come hai accennato: cambia il comportamento del compilatore.

La filosofia del linguaggio Perl è diversa dalla filosofia del pitone. Come in, ti viene data una corda più che sufficiente per impiccarti ripetutamente, in Perl.

Larry Wall è un grande appassionato di linguistica, quindi abbiamo da Perl quello che viene definito il principio TIMTOWTDI (diciamo tim-toe-dee ) vs. Zen di python:

  

Dovrebbe essercene uno-- e preferibilmente   solo un modo - obsoleto per farlo.

potresti facilmente usare pylint e PyChecker per trovare il tuo sapore di usa il rigoroso per python (o qualcosa di analogo a perl -cw * scriptname * ) ma a causa delle diverse filosofie nella progettazione del linguaggio, non lo incontrerai nella pratica ampiamente.

In base al tuo commento al primo poster, hai familiarità con importare questo da Python. Ci sono molte cose che spiegano perché non vedi un equivalente di usa strict in Python. Se mediti sul koan trovato nello Zen di Python, potresti trovare l'illuminazione per te stesso. :)

Ho scoperto che mi interessa davvero solo rilevare riferimenti a variabili non dichiarate. Eclipse ha l'integrazione di Pylint tramite PyDev e, sebbene Pylint sia tutt'altro che perfetto, fa un lavoro ragionevole in questo.

Va ??in qualche modo contro la natura dinamica di Python, e devo aggiungere occasionalmente #IGNOREs, quando il mio codice diventa intelligente su qualcosa. Ma trovo che ciò accada abbastanza raramente che ne sono felice.

Ma ho potuto vedere l'utilità di alcune funzionalità simili a pylint che diventano disponibili sotto forma di flag della riga di comando. Un po 'come l'opzione -3 di Python 2.6, che identifica i punti di incompatibilità tra il codice Python 2.xe 3.x.

È molto difficile scrivere programmi di grandi dimensioni senza 'usare rigoroso' in Perl. Senza "use strict", se si utilizza di nuovo una variabile e si scrive male lasciando una lettera fuori, il programma continua a funzionare. E senza casi di test per verificare i risultati, non è mai possibile trovare tali errori. Può essere molto dispendioso in termini di tempo scoprire perché stai ottenendo risultati errati a causa di questo motivo.

Alcuni dei miei programmi Perl sono composti da 5.000 righe a 10.000 righe di codice suddivise in decine di moduli. Non si può davvero programmare la produzione senza "usare rigorosamente". Non permetterei mai che il codice di produzione venga installato in fabbrica con lingue che non applicano "dichiarazioni variabili".

Questo è il motivo per cui Perl 5.12.x ora ha "use strict" come comportamento predefinito. Puoi disattivarli.

PHP mi ha dato alcuni problemi a causa della mancata applicazione della dichiarazione variabile. Quindi devi limitarti a piccoli programmi con questa lingua.

Solo un'opinione ...

abcParsing

Perl è un linguaggio sfrenato come si diceva :). Quindi puoi usare la variabile prima di annunciarla; Ad esempio: se usi un nome var " is_array " ma digita " is_arrby " , il compilatore non segnalerà errori senza " usa rigoroso " . Quindi, quando si codifica un programma lungo in perl, usare meglio "usare rigorosamente" dichiarazione. Naturalmente, meno di 50 righe per l'esecuzione di uno script una volta, non è necessario :)

Sembra l'ideale di " Pythonic " il codice ha lo stesso scopo di usa strict .

Non ho uno sfondo Perl, ma da quello che so, non esiste alcuna funzionalità in Python che deve essere disabilitata affinché il tuo codice sia "più affidabile", quindi in questo senso, immagino che tu possa dire che non è necessario

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top