python - subplots - Les instructions d'importation doivent-elles toujours figurer en haut d'un module?




window title python (10)

C'est comme beaucoup d'autres optimisations - vous sacrifiez une certaine lisibilité pour la vitesse. Comme John l'a mentionné, si vous avez fait vos devoirs de profilage et que vous avez trouvé que c'est un changement assez important et que vous avez besoin de la vitesse supplémentaire, alors allez-y. Il serait probablement bon de mettre une note avec toutes les autres importations:

from foo import bar
from baz import qux
# Note: datetime is imported in SomeClass below

Le PEP 08 stipule:

Les imports sont toujours placés en haut du fichier, juste après les commentaires et les docstrings du module, et avant les globals et les constantes du module.

Cependant, si la classe / méthode / fonction que j'importe est seulement utilisée dans de rares cas, il est sûrement plus efficace de faire l'importation quand cela est nécessaire.

N'est-ce pas:

class SomeClass(object):

    def not_often_called(self)
        from datetime import datetime
        self.datetime = datetime.now()

plus efficace que cela?

from datetime import datetime

class SomeClass(object):

    def not_often_called(self)
        self.datetime = datetime.now()

C'est un compromis, que seul le programmeur peut décider de faire.

Le cas 1 économise de la mémoire et du temps de démarrage en n'important pas le module datetime (et en faisant l'initialisation dont il a besoin) jusqu'à son utilisation. Notez que faire l'importation «seulement quand on l'appelle» signifie aussi le faire «chaque fois qu'il est appelé», de sorte que chaque appel après le premier entraîne toujours le surcoût supplémentaire de l'importation.

Le cas 2 permet d'économiser du temps d'exécution et de la latence en important au préalable la date et l'heure de sorte que not_often_called () revienne plus rapidement lors de l'appel, mais aussi en n'impliquant pas le coût d'une importation sur chaque appel.

Outre l'efficacité, il est plus facile de voir les dépendances des modules dès le début si les instructions d'importation sont ... à l'avant. En les cachant dans le code peut rendre plus difficile de trouver facilement quels modules quelque chose dépend.

Personnellement, je suis généralement le PEP à l'exception des choses comme les tests unitaires et tels que je ne veux pas toujours chargé parce que je sais qu'ils ne vont pas être utilisés, sauf pour le code de test.


En plus des excellentes réponses déjà données, il convient de noter que le placement des importations n'est pas seulement une question de style. Parfois, un module a des dépendances implicites qui doivent d'abord être importées ou initialisées, et une importation de niveau supérieur peut entraîner des violations de l'ordre d'exécution requis.

Ce problème survient souvent dans l'API Python d'Apache Spark, où vous devez initialiser le SparkContext avant d'importer des paquets ou des modules pyspark. Il est préférable de placer les importations de pyspark dans un périmètre où le SparkContext est garanti disponible.


Il est intéressant que pas une seule réponse mentionné traitement parallèle jusqu'à présent, où il pourrait être nécessaire que les importations sont dans la fonction, lorsque le code de fonction sérialisé est ce qui est poussé vers d'autres noyaux, comme dans le cas de ipyparallel.


Je n'aspire pas à fournir une réponse complète, car d'autres l'ont déjà fait très bien. Je veux juste mentionner un cas d'utilisation quand je trouve particulièrement utile d'importer des modules dans les fonctions. Mon application utilise des paquets python et des modules stockés à certains endroits en tant que plugins. Au démarrage de l'application, l'application parcourt tous les modules de l'emplacement et les importe, puis regarde à l'intérieur des modules et trouve des points de montage pour les plugins (dans mon cas c'est une sous-classe d'une classe de base ayant un ID) il les enregistre. Le nombre de plugins est grand (maintenant des dizaines, mais peut-être des centaines dans le futur) et chacun d'eux est utilisé assez rarement. Avoir des importations de bibliothèques tierces en haut de mes modules plugin était un peu pénalisé lors du démarrage de l'application. En particulier, certaines bibliothèques tierces sont lourdes à importer (par exemple, l'importation d'intrigues tente même de se connecter à Internet et de télécharger quelque chose qui ajoutait environ une seconde au démarrage). En optimisant les imports (en ne les appelant que dans les fonctions où ils sont utilisés) dans les plugins, j'ai réussi à réduire le démarrage de 10 secondes à 2 secondes. C'est une grosse différence pour mes utilisateurs.

Donc, ma réponse est non, ne mettez pas toujours les importations au sommet de vos modules.


Je ne m'inquiéterais pas trop de l'efficacité du chargement du module à l'avant. La mémoire occupée par le module ne sera pas très importante (à supposer qu'elle soit suffisamment modulaire) et le coût de démarrage sera négligeable.

Dans la plupart des cas, vous voulez charger les modules en haut du fichier source. Pour quelqu'un qui lit votre code, il est beaucoup plus facile de dire quelle fonction ou quel objet vient de quel module.

Une bonne raison d'importer un module ailleurs dans le code est s'il est utilisé dans une instruction de débogage.

Par exemple:

do_something_with_x(x0

Je pourrais déboguer ceci avec:

from pprint import pprint
pprint(x)
do_something_with_x(x)

Bien sûr, l'autre raison d'importer des modules ailleurs dans le code est si vous devez les importer dynamiquement. C'est parce que vous n'avez pratiquement pas le choix.

Je ne m'inquiéterais pas trop de l'efficacité du chargement du module à l'avant. La mémoire occupée par le module ne sera pas très importante (à supposer qu'elle soit suffisamment modulaire) et le coût de démarrage sera négligeable.


L'importation de module est assez rapide, mais pas instantanée. Cela signifie que:

  • Mettre les importations en haut du module est bien, car c'est un coût trivial qui n'est payé qu'une seule fois.
  • Si vous placez les importations dans une fonction, les appels vers cette fonction prendront plus de temps.

Donc, si vous vous souciez de l'efficacité, mettez les importations au sommet. Déplacez-les seulement dans une fonction si votre profilage montre que cela aiderait (vous avez profilé pour voir où améliorer les performances, non?)

Les meilleures raisons que j'ai vu pour effectuer des importations paresseuses sont:

  • Support de bibliothèque facultatif. Si votre code a plusieurs chemins qui utilisent des bibliothèques différentes, ne cassez pas si une bibliothèque facultative n'est pas installée.
  • Dans le __init__.py d'un plugin, qui peut être importé mais pas réellement utilisé. Les exemples sont les plugins Bazaar, qui utilisent le bzrlib de chargement bzrlib de bzrlib .

L'initialisation du module ne se produit qu'une seule fois - lors de la première importation. Si le module en question provient de la bibliothèque standard, vous l'importerez probablement d'autres modules de votre programme. Pour un module aussi répandu que datetime, il est également probable qu'il existe une dépendance pour un grand nombre d'autres bibliothèques standard. La déclaration d'importation coûterait très peu alors puisque l'initialisation du module aurait déjà eu lieu. Tout ce qu'il fait à ce stade lie l'objet module existant à la portée locale.

Ajoutez cette information à l'argument de lisibilité et je dirais qu'il est préférable d'avoir la déclaration d'importation au niveau du module.


La première variante est en effet plus efficace que la seconde lorsque la fonction est appelée soit zéro, soit une fois. Avec la deuxième et les invocations suivantes, cependant, l'approche «importer tous les appels» est en réalité moins efficace. Voir ce lien pour une technique de chargement paresseux qui combine le meilleur des deux approches en faisant une "importation paresseuse".

Mais il y a des raisons autres que l'efficacité pourquoi vous pourriez préférer l'un à l'autre. Une approche rend beaucoup plus clair à quelqu'un qui lit le code quant aux dépendances que ce module a. Ils ont également des caractéristiques de défaillance très différentes - la première échouera au moment du chargement s'il n'y a pas de module "datetime" alors que la seconde n'échouera pas avant l'appel de la méthode.

Note ajoutée: Dans IronPython, les importations peuvent être un peu plus chères que dans CPython car le code est en train d'être compilé lors de son importation.


Mettre l'instruction import dans une fonction peut empêcher les dépendances circulaires. Par exemple, si vous avez deux modules, X.py et Y.py, et qu'ils doivent tous deux s'importer, cela provoquera une dépendance circulaire lorsque vous importerez l'un des modules provoquant une boucle infinie. Si vous déplacez l'instruction d'importation dans l'un des modules, il n'essaiera pas d'importer l'autre module avant l'appel de la fonction, et ce module sera déjà importé, donc pas de boucle infinie. Lisez ici pour plus d'informations - effbot.org/zone/import-confusion.htm





coding-style