2010-08-26 13 views
23

Se vi capita di averePython: Perché 'da <module> importazione *' deve essere vietato?

from <module> import * 

nel bel mezzo del programma (o modulo), si otterrebbe l'avvertimento:

/tmp/foo:100: SyntaxWarning: import * only allowed at module level 

capisco perché import * è sconsigliato in generale (invisibilità namespace) , ma ci sono molte situazioni in cui sarebbe conveniente, specialmente dove il codice non è condiviso con nessuno.

Quindi, qualcuno può spiegare con precisione in dettaglio perché from <module> import * dovrebbe essere vietato in tutti i casi possibili?

+0

quale ID si sta utilizzando e quale avviso? – avi

+0

Ho scritto un post sul blog che spiega perché questo deve essere vietato nell'ambito non globale: https://www.lesinskis.com/TIL_python_imports.html – shuttle87

risposta

19

credo da "nel mezzo del programma" si sta parlando di un'importazione all'interno una definizione di funzione:

def f(): 
    from module import * # not allowed 

Ciò non è consentito perché renderebbe l'ottimizzazione del corpo della funzione troppo difficile. L'implementazione Python vuole conoscere tutti i nomi delle variabili locali della funzione quando esso calcola in byte una funzione, in modo che possa ottimizzare i riferimenti variabili nelle operazioni sullo stack operand della macchina virtuale (CPython) o almeno nello slot variabile locale operazioni piuttosto che ricerche nei namespace esterni. Se si potesse scaricare l'intero contenuto di un modulo nello spazio dei nomi locale di una funzione, il compilatore dovrebbe assumere che il nome nella funzione potrebbe riferirsi a un modulo globale, poiché l'elenco di nomi introdotto da from module import * è solo conosciuto in fase di esecuzione.

Mettere from module import *in tra dichiarazioni di livello superiore è stile povero, ma è consentito:

def f(): 
    ... 

from module import * 

def g(): 
    ... 

EDIT aprile 2013: Mentre cerca in qualcosa d'altro, ho scoperto che questa restrizione è stata introdotta in Python 2.1, come conseguenza dello "Nested Scopes" feature (PEP 227). Citando dal link:

effetto

Un lato del cambiamento è che le dichiarazioni from module import * e exec sono state fatte illegale all'interno di un insieme di funzioni determinate condizioni. Il manuale di riferimento di Python ha affermato che from module import * è legale solo al livello più alto di un modulo, ma l'interprete CPython non l'ha mai applicato prima. Come parte dell'implementazione degli ambiti nidificati, il compilatore che trasforma il sorgente Python in bytecode deve generare un codice diverso per accedere alle variabili in un ambito di contenimento. from module import * e exec rendono impossibile al compilatore di capirlo, perché aggiungono nomi allo spazio dei nomi locale che sono inconoscibili in fase di compilazione. Pertanto, se una funzione contiene le definizioni di funzione o le espressioni lambda con variabili libere, il compilatore lo contrassegnerà sollevando un'eccezione SyntaxError.

Questo chiarisce il comportamento di Python 3.x vs 2. discusso nei commenti. È sempre contrario alle specifiche del linguaggio, ma CPython 2.1 a 2.7 emette un errore per from module import * all'interno di una funzione solo se può influire sulla capacità del compilatore di sapere se una variabile esegue il binding localmente o in un ambito di contenimento. In 3.x è stato promosso a un errore incondizionato.

SON OF EDIT: ... e apparentemente flashk lo ha sottolineato anni fa in un'altra risposta, citando lo stesso paragrafo di "Novità in Python 2.1" ancora. Lo fai andare adesso.

+3

Grazie per l'analisi, Zack. Sembra: (1) 'import *' è permesso in un corpo di funzione (con un avvertimento) se non è, o non ha, alcun blocco annidato; (2) Anche se il documento di Python dice che non è permesso tranne che al livello più alto di un modulo, non viene mai applicato (vale a dire, ancora possibile); (3) Se il compilatore di byte può eseguire il modulo in modo che conosca tutte le variabili e le funzioni, non sarà un problema per l'ottimizzazione; (4) Mostrami solo un esempio di cosa è andato storto con lo scope nidificato, Python. – OTZ

+0

@Zack - Le variabili libere sono quelle vincolate in un ambito che racchiude. Quindi se si ha un assegnamento globale del modulo 'x = 3' e una funzione' def foo(): print x', allora x è una variabile libera di foo. Non è una parola da donnola - vedi http://docs.python.org/reference/executionmodel.html per la definizione. "Se una variabile viene utilizzata in un blocco di codice ma non è definita lì, è una variabile libera." –

+0

@Jeremy: Ciò che intendevo con "parole di donnola" è che la regola della lingua è che puoi usare "da X import *" solo nell'ambito del modulo, ma l'implementazione (a quanto pare) la applica solo in circostanze limitate. – zwol

11

La release notes for Python 2.1 sembrano spiegare perché questa limitazione esiste:

effetto

Un lato del cambiamento è che i dal modulo di importazione * e exec dichiarazioni sono state fatte illegale all'interno di un ambito di funzione a determinate condizioni. Il manuale di riferimento Python ha affermato che dal modulo l'importazione * è legale solo al livello superiore di un modulo, ma l'interprete CPython non ha mai applicato prima questo . Come parte dell'implementazione degli ambiti nidificati, il compilatore che trasforma in byte bytecode in Python ha variabili per accedere alle variabili in un ambito di contenimento. da modulo import * ed exec lo rendono impossibile per il compilatore di figura , perché aggiungono nomi a lo spazio dei nomi locale che è inconoscibile al momento della compilazione. Pertanto, se una funzione contiene le definizioni o le espressioni lambda con le variabili libere , il compilatore contrassegnerà sollevando un'eccezione SyntaxError .

+0

OK. Quindi, non sarebbe "import *" reso possibile se il compilatore di byte esegue in "da import *" al momento della compilazione in modo che conosca tutte le variabili e le funzioni contenute nel modulo? Perché non dovrebbe farlo? – OTZ

+0

Per prima cosa, il '' potrebbe non esistere quando il codice contenente l'istruzione import è compilato. Oppure il set di variabili da importare può cambiare tra "tempo di compilazione" e "tempo di esecuzione". –

1

Non è affatto vietato. Funziona bene, ma ricevi un avvertimento perché è generalmente una cattiva idea (per ragioni che sono state fatte ad altri). Puoi, se vuoi, sopprimere l'avvertimento; il modulo di avvertimenti è ciò che vuoi per quello.

15

A qualsiasi livello lessicale, from amodule import * è un "sembrava una buona idea, al momento" decisione di progettazione che si è dimostrato un vero e proprio disastro nella vita reale, con la possibile eccezione di esplorazione a portata di mano al prompt interprete interattivo (anche allora , Non ci sto troppo caldo - import module as m obbliga solo due caratteri in più ad usare nomi qualificati invece [[solo un prefisso m.]], e i nomi qualificati sono sempre più nitidi e flessibili dei nomi dei baristi, per non parlare del grande utilità in situazioni interattive esplorative di avere m disponibile per help(m), reload(m) e simili!).

Questo costrutto lacerato lo rende molto difficile, per la persona povera che legge il codice (spesso in un tentativo fallito di aiutarlo a debuggarlo) per capire da dove provengono nomi misteriosi - impossibile, se il costrutto viene usato di più di una volta a livello lessicale; ma anche se usato una sola volta, costringe a rileggere laboriosamente l'intero modulo ogni volta prima che uno possa convincersi che, sì, quel barname in disordine deve provenire dal modulo.

Inoltre, gli autori dei moduli di solito non vanno nei guai estremi necessari per "supportare" l'odioso costrutto in questione. Se da qualche parte nel tuo codice hai, per esempio, un uso di sys.argv (e uno import sys nella parte più alta del tuo modulo, ovviamente), come fai a sapere che sys è il modulo che dovrebbe essere ... o alcuni completamente diverso uno (o un non modulo) proveniente dallo ... import *?!Moltiplicate quello con tutti i nomi qualificati che state usando e la miseria è l'unico risultato finale - quello, e misteriosi bug che richiedono un debug lungo e laborioso (di solito con l'aiuto riluttante di qualcuno che fa "get" Python ... ! -).

All'interno di una funzione, un modo per aggiungere e ignorare nomi locali arbitrari sarebbe anche peggio. Come elementare ma cruciale ottimizzazione, il compilatore Python controlla il corpo della funzione per qualsiasi assegnazione o altre istruzioni di binding su ogni barename, e considera "local" quei nomi che vede così assegnati (gli altri devono essere globali o built-in). Con un import * (proprio come con un exec somestring senza dict esplicito da utilizzare come spazi dei nomi), improvvisamente diventa un mistero totale quali nomi sono locali, quali nomi sono globali, quindi il compilatore povero dovrebbe ricorrere alla strategia più lenta possibile per ogni ricerca del nome, usando un dict per le variabili locali (invece del "vettore" compatto che normalmente utilizza) e eseguendo fino a tre ditt di look-up per ogni barename a cui si fa riferimento, più e più volte.

Passare a qualsiasi prompt interattivo Python. Digitare import this. Cosa vedi? Lo Zen di Python. Qual è l'ultimo e probabilmente il più grande pezzo di saggezza in quel testo ...?

Gli spazi dei nomi sono una delle grandi idee - facciamolo di più!

Forzando l'uso di barenames cui nomi qualificati sono così di gran lunga preferibile, si sta essenzialmente facendo il contrario di questo saggio raccomandazione molto : invece di ammirare la grandezza e honkingtude di spazi dei nomi, e fare di più di quelli, sei che scompone due spazi dei nomi perfettamente funzionanti e pronti per l'uso (quello del modulo che stai importando e quello dell'ambito lessicale in cui lo stai importando) per creare un singolo, empio, caos buggy, lento, rigido, inutilizzabile.

Se potessi tornare indietro e cambiare uno decisione di progettazione iniziale in Python (si tratta di una scelta difficile, perché l'uso di def e soprattutto per quello che lambda Javascript così chiama molto di più essere letti function è un secondo vicino ;-), Vorrei cancellare retroattivamente l'idea di import * dalla mente di Guido. Nessuna quantità di presunta convenienza per l'esplorazione al prompt interattivo in grado di bilanciare la quantità del male è battuto ... -!)

+2

+1 honkingtude: P –

+0

Ma, ma! In pratica, è veramente ** 100 utile. Supponiamo che tu abbia una libreria di utilità canonica e generica, ad esempio "aima/utils.py" di Peter Norvig. Non voglio aggiungere "m". decine di volte in tutte le sessioni interattive e in qualsiasi sceneggiatura sto scrivendo estemporaneamente per riferirsi alle funzioni utili nella libreria. Sto dicendo: se sei sicuro che nulla sarà e sarebbe in conflitto con il namespace locale di "import *" e se sei pienamente consapevole di tutti i moduli importati, perché eliminare la comodità? Naturalmente, dovrebbe essere scoraggiato in un progetto di più di un ingegnere. – OTZ

+4

"perché eliminare la comodità?" - è noto come un "fastidioso disturbo" negli ambienti legali: una presunta "convenienza" che attira le persone alla loro rovina (e, in questo caso, è esattamente contraria ai principi chiave di Python, come ho dimostrato). Python è normalmente piuttosto bravo in questo, ma "... import *" è un'eccezione sfortunata. Per esempio, guarda tutte le sue occorrenze su SO, e inizierai a vedere quale terreno fertile per bug, difficoltà e perplessità. Vuoi concisione a tutti i costi?Quindi Python non è per te: potenza, chiarezza, eleganza, sì, estrema concisione, ** no **. –

0

altri hanno dato risposte approfondite, ti darò una risposta breve panoramica della mia comprensione .. quando usi da te lo stai facendo così puoi chiamare direttamente qualsiasi funzione in quel modulo che hai importato senza fare modulename.functioname (puoi semplicemente chiamare "functionname") questo crea problemi se hai 2 funzioni con lo stesso nome in diversi moduli e può anche creare confusione quando si ha a che fare con molte funzioni perché non si conosce a quale oggetto/modulo appartiene (dal punto di vista di qualcuno che sta guardando codice già scritto che non ha familiarità con esso)

4

Non è proibito, perché ...

... è a portata di mano per gli script di shell veloci e esplorare.

...ma non si dovrebbe tenere in qualsiasi codice serio

  1. può portare a importare nomi che non si conoscono e cancellare nomi locali
  2. non si può sapere che cosa è in uso nel codice, è difficile di conoscere uno script dipendenze
  3. completamenti codice non funzionerà correttamente più
  4. IDE convenienti controlli come "questo var non è stato dichiarato" non può più lavorare
  5. lo rendono più facile creare le importazioni circolari
Problemi correlati