Domanda

PEP 8 dice:

  
      
  • Le importazioni vengono sempre inserite nella parte superiore del file, subito dopo qualsiasi modulo   commenti e docstring e prima dei globuli e delle costanti del modulo.
  •   

A volte, violo PEP 8. Alcune volte importare roba all'interno di funzioni. Come regola generale, lo faccio se esiste un'importazione utilizzata solo all'interno di una singola funzione.

Qualche opinione?

MODIFICA (il motivo per cui mi sento importare nelle funzioni può essere una buona idea):

Motivo principale: può rendere il codice più chiaro.

  • Quando guardo il codice di una funzione potrei chiedermi: " Che cos'è la funzione / classe xxx? " (xxx utilizzato all'interno della funzione). Se ho tutte le mie importazioni nella parte superiore del modulo, devo andare a cercare lì per determinare cos'è xxx. Questo è più un problema quando si utilizza da m import xxx . Vedere m.xxx nella funzione probabilmente mi dice di più. A seconda di cosa sia m : è un modulo / pacchetto di primo livello ben noto ( import m )? Oppure è un sottomodulo / pacchetto ( da a.b.c import m )?
  • In alcuni casi, avere informazioni extra (" What is xxx? ") vicino a dove viene usato xxx può rendere la funzione più facile da capire.
È stato utile?

Soluzione

A lungo termine penso che apprezzerai avere la maggior parte delle tue importazioni nella parte superiore del file, in questo modo puoi capire a colpo d'occhio quanto il tuo modulo sia complicato da ciò che deve importare.

Se sto aggiungendo un nuovo codice a un file esistente di solito eseguirò l'importazione dove è necessario e quindi se il codice rimane, renderò le cose più permanenti spostando la riga di importazione nella parte superiore del file.

Un altro punto, preferisco ottenere un'eccezione ImportError prima che venga eseguito qualsiasi codice, come controllo di integrità, quindi questo è un altro motivo per importare in alto.

Uso pyChecker per verificare la presenza di moduli non utilizzati.

Altri suggerimenti

Ci sono due occasioni in cui violo PEP 8 al riguardo:

  • Importazioni circolari: il modulo A importa il modulo B, ma qualcosa nel modulo B ha bisogno del modulo A (anche se questo è spesso un segnale che devo riformattare i moduli per eliminare la dipendenza circolare)
  • Inserimento di un breakpoint pdb: import pdb; pdb.set_trace () Questo è utile b / c Non voglio mettere import pdb nella parte superiore di ogni modulo che potrei voler eseguire il debug ed è facile ricordare di rimuovere l'importazione quando rimuovo il punto di interruzione.

Al di fuori di questi due casi, è una buona idea mettere tutto in cima. Rende le dipendenze più chiare.

Ecco i quattro casi d'uso di importazione che utilizziamo

  1. import (e da x import y e import x as y ) in alto

  2. Scelte per l'importazione. Nella parte superiore.

    import settings
    if setting.something:
        import this as foo
    else:
        import that as foo
    
  3. Importazione condizionale. Utilizzato con JSON, librerie XML e simili. Nella parte superiore.

    try:
        import this as foo
    except ImportError:
        import that as foo
    
  4. Importazione dinamica. Finora, abbiamo solo un esempio di questo.

    import settings
    module_stuff = {}
    module= __import__( settings.some_module, module_stuff )
    x = module_stuff['x']
    

    Nota che questa importazione dinamica non porta il codice, ma porta il complesso strutture dati scritte in Python. È un po 'come un pezzo di dati in salamoia tranne che l'abbiamo sottaceto a mano.

    Questo è anche, più o meno, all'inizio di un modulo


Ecco cosa facciamo per rendere il codice più chiaro:

  • Mantieni i moduli brevi.

  • Se ho tutte le mie importazioni nella parte superiore del modulo, devo andare a cercare lì per determinare quale sia un nome. Se il modulo è corto, è facile da fare.

  • In alcuni casi, avere informazioni extra vicine a dove viene usato un nome può rendere la funzione più facile da capire. Se il modulo è corto, è facile da fare.

Una cosa da tenere a mente: importazioni inutili possono causare problemi di prestazioni. Quindi, se questa è una funzione che verrà chiamata frequentemente, è meglio mettere l'importazione in alto. Ovviamente questo è un'ottimizzazione, quindi se c'è un caso valido per cui l'importazione all'interno di una funzione è più chiara dell'importazione nella parte superiore di un file, questo supera le prestazioni nella maggior parte dei casi.

Se stai facendo IronPython, mi viene detto che è meglio importare funzioni interne (poiché la compilazione del codice in IronPython può essere lenta). Quindi, potresti essere in grado di ottenere un modo con l'importazione all'interno delle funzioni. Ma a parte questo, direi che non vale la pena combattere la convenzione.

  

Come regola generale, lo faccio se esiste un'importazione utilizzata solo all'interno di una singola funzione.

Un altro punto che vorrei sottolineare è che questo potrebbe essere un potenziale problema di manutenzione. Cosa succede se si aggiunge una funzione che utilizza un modulo precedentemente utilizzato da una sola funzione? Ricorderai di aggiungere l'importazione all'inizio del file? O hai intenzione di scansionare ogni singola funzione per l'importazione?

FWIW, ci sono casi in cui ha senso importare all'interno di una funzione. Ad esempio, se si desidera impostare la lingua in cx_Oracle, è necessario impostare una variabile di ambiente LANG _ LANG prima di da importare. Pertanto, potresti vedere un codice come questo:

import os

oracle = None

def InitializeOracle(lang):
    global oracle
    os.environ['NLS_LANG'] = lang
    import cx_Oracle
    oracle = cx_Oracle

Ho infranto questa regola in precedenza per i moduli che sono autotest. Cioè, normalmente sono solo usati per il supporto, ma io definisco un main per loro in modo che se li esegui da soli puoi testare la loro funzionalità. In tal caso, a volte importare getopt e cmd proprio in linea di principio, perché voglio che sia chiaro a qualcuno che legge il codice che questi moduli non hanno nulla a che fare con il normale funzionamento del modulo e vengono inclusi solo per i test.

Proveniente dalla domanda sul caricare il modulo due volte - Perché non entrambi?

Un'importazione nella parte superiore dello script indicherà le dipendenze e un'altra importazione nella funzione renderà questa funzione più atomica, mentre apparentemente non causa alcun svantaggio di prestazioni, poiché un'importazione consecutiva è economica.

Finché è import e non da x import * , dovresti metterli in alto. Aggiunge solo un nome allo spazio dei nomi globale e ti attieni a PEP 8. Inoltre, se in seguito ne hai bisogno da qualche altra parte, non devi spostare nulla.

Non è un grosso problema, ma poiché non c'è quasi alcuna differenza, suggerirei di fare ciò che dice PEP 8.

Dai un'occhiata all'approccio alternativo che viene utilizzato in sqlalchemy: dependency injection:

@util.dependencies("sqlalchemy.orm.query")
def merge_result(query, *args):
    #...
    query.Query(...)

Nota come la libreria importata viene dichiarata in un decoratore e trasmessa come argomento alla funzione !

Questo approccio rende il codice più pulito e funziona anche 4,5 volte più veloce di un'istruzione import !

Indice di riferimento: https://gist.github.com/kolypto/589e84fbcfb63125326 <6656 p>

scroll top