153 votes

Est-ce que c'est pythonique d'importer à l'intérieur des fonctions ?

PEP 8 dit :

  • Les importations sont toujours placées en tête de fichier, juste après les modules. et la documentation, et avant les globales et constantes du module.

Il m'arrive de violer le PEP 8. Parfois, j'importe des éléments à l'intérieur de fonctions. En règle générale, je le fais si une importation n'est utilisée qu'au sein d'une seule fonction.

Des avis ?

EDIT (la raison pour laquelle je pense que l'importation dans les fonctions peut être une bonne idée) :

Principale raison : cela peut rendre le code plus clair.

  • Lorsque je regarde le code d'une fonction, je peux me demander : "Qu'est-ce que la fonction/classe xxx ?" (xxx étant utilisé à l'intérieur de la fonction). Si tous mes imports se trouvent en haut du module, je dois aller voir là pour déterminer ce qu'est xxx. Le problème se pose davantage lorsque l'on utilise from m import xxx . Voir m.xxx dans la fonction m'en dit probablement plus. En fonction de ce que m est : S'agit-il d'un module/paquet de premier niveau bien connu ( import m ) ? Ou s'agit-il d'un sous-module/paquet ( from a.b.c import m ) ?
  • Dans certains cas, le fait de disposer de cette information supplémentaire ("Qu'est-ce que xxx ?") à proximité de l'endroit où xxx est utilisé peut faciliter la compréhension de la fonction.

5voto

IljaBek Points 333

En partant de la question de la charger le module deux fois - Pourquoi pas les deux ?

Un import en tête du script indiquera les dépendances et un autre import dans la fonction rendra cette fonction plus atomique, tout en ne causant apparemment pas de désavantage en termes de performances, puisqu'un import consécutif est peu coûteux.

5voto

kolypto Points 3161

Jetez un coup d'œil à l'approche alternative utilisée dans sqlalchemy : l'injection de dépendances :

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

Remarquez que la bibliothèque importée est déclarée dans un décorateur et qu'elle est transmise à l'application comme argument de la fonction !

Cette approche rend le code plus propre et fonctionne également 4,5 fois plus rapide qu'un import déclaration !

Critères d'évaluation : https://gist.github.com/kolypto/589e84fbcfb6312532658df2fabdb796

4voto

ZioByte Points 317

Il existe un autre cas (probablement "en coin") où il peut être avantageux de import à l'intérieur des fonctions rarement utilisées : raccourcir le temps de démarrage.

Je me suis heurté à ce mur une fois avec un programme assez complexe fonctionnant sur un petit serveur IoT qui acceptait des commandes provenant d'une ligne série et effectuait des opérations, parfois très complexes.

Placement import au début des fichiers destinés à avoir des tous traitées avant le démarrage du serveur ; puisque import liste incluse jinja2 , lxml , signxml et d'autres "poids lourds" (et le SoC n'était pas très puissant). minutes avant que la première instruction ne soit effectivement exécutée.

En revanche, en plaçant la plupart des importations dans des fonctions, j'ai pu rendre le serveur "vivant" sur la ligne série en quelques secondes. Bien sûr, lorsque les modules étaient réellement nécessaires, je devais en payer le prix (Note : ceci peut également être atténué en créant une tâche d'arrière-plan qui fait import en temps d'inactivité).

3voto

Javier Badia Points 1996

Tant qu'il est import et non from x import * Vous devriez les placer en tête de liste. Cela n'ajoute qu'un seul nom à l'espace de noms global, et vous vous en tenez à la PEP 8. De plus, si vous en avez besoin ultérieurement ailleurs, vous n'aurez pas à déplacer quoi que ce soit.

Ce n'est pas grave, mais comme il n'y a pratiquement pas de différence, je suggère de faire ce que dit le PEP 8.

3voto

codeape Points 38576

Dans les modules qui sont à la fois des modules "normaux" et qui peuvent être exécutés (c'est-à-dire qui ont une fonction if __name__ == '__main__': -), j'importe généralement des modules qui ne sont utilisés que lors de l'exécution du module dans la section principale.

Exemple :

def really_useful_function(data):
    ...

def main():
    from pathlib import Path
    from argparse import ArgumentParser
    from dataloader import load_data_from_directory

    parser = ArgumentParser()
    parser.add_argument('directory')
    args = parser.parse_args()
    data = load_data_from_directory(Path(args.directory))
    print(really_useful_function(data)

if __name__ == '__main__':
    main()

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X