Les instructions d'importation doivent-elles toujours être en haut d'un module?

403

PEP 08 déclare:

Les importations sont toujours placées en haut du fichier, juste après les commentaires et les docstrings de module, et avant les globales et les constantes du module.

Cependant, si la classe / méthode / fonction que j'importe n'est utilisée que dans de rares cas, il est sûrement plus efficace de faire l'importation quand elle 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 ça?

from datetime import datetime

class SomeClass(object):

    def not_often_called(self)
        self.datetime = datetime.now()
Adam J. Forster
la source

Réponses:

283

L'importation de modules 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.
  • Placer les importations dans une fonction entraînera un délai plus long pour les appels à cette fonction.

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


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

  • Prise en charge de la bibliothèque en option. Si votre code a plusieurs chemins qui utilisent différentes bibliothèques, ne vous arrêtez pas si une bibliothèque facultative n'est pas installée.
  • Dans le __init__.pyplugin, qui peut être importé mais pas réellement utilisé. Les plugins Bazaar, par exemple, utilisent bzrlible framework de chargement différé de.
John Millikin
la source
17
John, c'était une question complètement théorique, donc je n'avais pas de code à profiler. Dans le passé, j'ai toujours suivi le PEP, mais j'ai écrit un code aujourd'hui qui m'a fait me demander si c'était la bonne chose à faire. Merci de votre aide.
Adam J.Forster, le
43
> Placer les importations dans une fonction entraînera un appel plus long à cette fonction. En fait, je pense que ce coût n'est payé qu'une seule fois. J'ai lu que Python met en cache un module importé de sorte qu'il n'y a qu'un coût minime pour l'importer à nouveau.
fondu le
24
@halfhourhacks Python ne réimportera pas le module, mais il doit quand même exécuter quelques instructions juste pour voir si le module existe / est dans sys.modules / etc.
John Millikin
24
-1. Placer des importations dans une fonction n'entraîne pas nécessairement son allongement. Veuillez voir ma réponse sur une autre question.
aaronasterling le
4
Un cas d'utilisation consiste à éviter les importations circulaires (généralement peu judicieuses, mais parfois adaptées). Parfois, la classe A du module m1 appelle une méthode de la classe B du module m2 qui construit une autre instance de la classe A. Si la méthode de la classe B qui construit une instance de la classe A a l'importation exécutée uniquement lors de l'exécution de la fonction qui construit une instance, l'importation circulaire est évitée.
Sam Svenbjorgchristiensensen
80

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

Moe
la source
3
Oui mais on peut entrer dans l'enfer des dépendances.
eigenein
8
Si deux modules doivent s'importer, quelque chose ne va vraiment pas avec le code.
Anna
La programmation orientée objet me conduit souvent à des dépendances circulaires. Une classe d'objets vitale peut être importée dans plusieurs modules. Pour que cet objet exécute ses propres tâches, il peut être nécessaire d'atteindre un ou plusieurs de ces modules. Il existe des moyens de l'éviter, comme l'envoi de données à l'objet via des arguments de fonction, pour lui permettre d'accéder à l'autre module. Mais il y a des moments où cela semble très contre-intuitif pour la POO (le monde extérieur ne devrait pas avoir besoin de savoir comment il accomplit la tâche dans cette fonction).
Robert
4
Lorsque X a besoin de Y et Y a besoin de X, ce sont soit deux parties de la même idée (c'est-à-dire doivent être définies ensemble), soit il y a une abstraction manquante.
GLRoman
59

J'ai adopté la pratique de mettre toutes les importations dans les fonctions qui les utilisent, plutôt qu'en haut du module.

L'avantage que j'obtiens est la capacité de refactoriser de manière plus fiable. Lorsque je déplace une fonction d'un module à un autre, je sais que la fonction continuera de fonctionner avec tout son héritage de test intact. Si j'ai mes importations en haut du module, lorsque je déplace une fonction, je trouve que je passe beaucoup de temps à obtenir les importations du nouveau module complètes et minimales. Un IDE de refactoring pourrait rendre cela non pertinent.

Il y a une pénalité de vitesse comme mentionné ailleurs. J'ai mesuré cela dans ma candidature et l'ai trouvé insignifiant pour mes besoins.

Il est également agréable de pouvoir voir toutes les dépendances de module à l'avance sans avoir recours à la recherche (par exemple grep). Cependant, la raison pour laquelle je me soucie des dépendances de module est généralement parce que j'installe, refactorise ou déplace un système entier comprenant plusieurs fichiers, pas seulement un seul module. Dans ce cas, je vais quand même effectuer une recherche globale pour m'assurer d'avoir les dépendances au niveau du système. Je n'ai donc pas trouvé d'importations mondiales pour m'aider à comprendre un système dans la pratique.

Je mets généralement l'importation de l' sysintérieur du if __name__=='__main__'chèque, puis passe des arguments (comme sys.argv[1:]) à une main()fonction. Cela me permet d'utiliser maindans un contexte où sysn'a pas été importé.


la source
4
De nombreux IDE facilitent la refactorisation du code en optimisant et en important automatiquement les modules nécessaires dans votre fichier. Dans la majorité des cas, PyCharm et Eclipse ont pris les bonnes décisions pour moi. Je parierais qu'il existe un moyen d'obtenir le même comportement dans emacs ou vim.
brent.payne
3
Une importation à l'intérieur d'une instruction if dans l'espace de noms global est toujours une importation globale. Cela affichera les arguments (en utilisant Python 3): def main(): print(sys.argv); if True: import sys; main();Vous devrez encapsuler if __name__=='__main__'dans une fonction pour créer un nouvel espace de noms.
Darcinon
4
Cela me semble être une excellente raison d'importer au sein des fonctions plutôt que dans le cadre mondial. Je suis assez surpris que personne d'autre n'ait mentionné le faire pour cette même raison. Y a-t-il des inconvénients importants, outre les performances et la verbosité?
algal
@algal l'inconvénient est que beaucoup de gens python détestent cela parce que vous violez le codex pep. Vous devez convaincre les membres de votre équipe. La pénalité de performance est minime. Parfois , il est encore plus rapide, voir stackoverflow.com/a/4789963/362951
mit
Je l'ai trouvé extrêmement utile pour refactoriser les importations près de l'endroit où je les utilise. Il n'est plus nécessaire de faire défiler vers le haut et vers l'arrière tant de temps. J'utilise des IDE comme pycharm ou wing ide et j'utilise aussi leur refactoring, mais je ne veux pas toujours me fier à eux. Déplacer des fonctions vers un autre module devient beaucoup plus facile avec ce style d'importation alternatif, par conséquent je refactorise beaucoup plus.
mit
39

La plupart du temps, cela serait utile pour plus de clarté et raisonnable, mais ce n'est pas toujours le cas. Vous trouverez ci-dessous quelques exemples de circonstances dans lesquelles les importations de modules peuvent vivre ailleurs.

Tout d'abord, vous pourriez avoir un module avec un test unitaire de la forme:

if __name__ == '__main__':
    import foo
    aa = foo.xyz()         # initiate something for the test

Deuxièmement, vous devrez peut-être importer conditionnellement un module différent lors de l'exécution.

if [condition]:
    import foo as plugin_api
else:
    import bar as plugin_api
xx = plugin_api.Plugin()
[...]

Il existe probablement d'autres situations dans lesquelles vous pouvez placer des importations dans d'autres parties du code.

ConcernedOfTunbridgeWells
la source
14

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 invocation et les suivantes, cependant, l'approche "importer chaque appel" est en fait moins efficace. Voir ce lien pour une technique de chargement paresseux qui combine le meilleur des deux approches en effectuant une «importation paresseuse».

Mais il y a des raisons autres que l'efficacité pour lesquelles vous pourriez préférer l'une à l'autre. Une approche est de rendre beaucoup plus clair pour quelqu'un qui lit le code les dépendances de ce module. Ils ont également des caractéristiques de défaillance très différentes - le premier échouera au moment du chargement s'il n'y a pas de module "datetime" tandis que le second n'échouera pas jusqu'à ce que la méthode soit appelée.

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

Curt Hagenlocher
la source
1
Ce n'est pas vrai que le premier fonctionne mieux: wiki.python.org/moin/PythonSpeed/…
Jason Baker
Il fonctionne mieux si la méthode n'est jamais appelée car l'importation ne se produit jamais.
Curt Hagenlocher
Vrai, mais il fonctionne moins bien si la méthode est appelée plusieurs fois. Et les avantages en termes de performances que vous gagneriez à ne pas importer le module immédiatement sont négligeables dans la plupart des cas. Les exceptions seraient si le module est très grand ou s'il y a beaucoup de ces types de fonctions.
Jason Baker,
Dans le monde IronPython, les importations initiales sont beaucoup plus chères qu'en CPython;). L'exemple "importation paresseuse" dans votre lien est probablement la meilleure solution générique globale.
Curt Hagenlocher
J'espère que cela ne vous dérange pas, mais je l'ai édité dans votre message. Ce sont des informations utiles à savoir.
Jason Baker, le
9

Curt fait un bon point: la deuxième version est plus claire et échouera au moment du chargement plutôt que plus tard, et de manière inattendue.

Normalement, je ne m'inquiète pas de l'efficacité du chargement des modules, car c'est (a) assez rapide, et (b) ne se produit généralement qu'au démarrage.

Si vous devez charger des modules lourds à des moments inattendus, il est probablement plus logique de les charger dynamiquement avec la __import__fonction, et assurez-vous de détecter les ImportErrorexceptions et de les gérer de manière raisonnable.

Dan Lenski
la source
8

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 grande (en supposant qu'elle soit suffisamment modulaire) et le coût de démarrage sera négligeable.

Dans la plupart des cas, vous souhaitez charger les modules en haut du fichier source. Pour quelqu'un qui lit votre code, il est beaucoup plus facile de savoir quelle fonction ou quel objet provient 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(x)

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 grande (en supposant qu'elle soit suffisamment modulaire) et le coût de démarrage sera négligeable.

Jason Baker
la source
Nous parlons de dizaines de millisecondes de coût de démarrage par module (sur ma machine). Ce n'est pas toujours négligeable, par exemple si cela affecte la réactivité d'une application Web à un clic d'utilisateur.
Evgeni Sergeev
6

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 qu'il pourrait nécessiter) jusqu'à ce qu'il soit nécessaire. Notez que faire l'importation «uniquement lorsqu'il est appelé» signifie également le faire «à chaque fois appelé», de sorte que chaque appel après le premier entraîne toujours une surcharge supplémentaire liée à l'importation.

Le cas 2 permet d'économiser du temps d'exécution et de la latence en important au préalable datetime afin que not_often_called () revienne plus rapidement lorsqu'il est appelé, et également en n'encourant pas la surcharge d'une importation à chaque appel.

Outre l'efficacité, il est plus facile de voir les dépendances du module à l'avant si les instructions d'importation sont ... à l'avant. Les masquer dans le code peut rendre plus difficile de trouver facilement les modules dont dépend quelque chose.

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

pjz
la source
2
-1. Le surcoût principal de l'importation ne se produit que la première fois. Le coût de recherche du module sys.modulespeut facilement être compensé par les économies réalisées en ne cherchant qu'un nom local au lieu d'un nom global.
aaronasterling
6

Voici un exemple où toutes les importations sont au sommet (c'est la seule fois que j'ai besoin de le faire). Je veux pouvoir terminer un sous-processus sur Un * x et Windows.

import os
# ...
try:
    kill = os.kill  # will raise AttributeError on Windows
    from signal import SIGTERM
    def terminate(process):
        kill(process.pid, SIGTERM)
except (AttributeError, ImportError):
    try:
        from win32api import TerminateProcess  # use win32api if available
        def terminate(process):
            TerminateProcess(int(process._handle), -1)
    except ImportError:
        def terminate(process):
            raise NotImplementedError  # define a dummy function

(En révision: ce que John Millikin a dit.)

giltay
la source
6

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 avez trouvé que c'était un changement suffisamment utile 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
Drew Stephens
la source
4

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 pourrez également l'importer à partir d'autres modules de votre programme. Pour un module aussi répandu que datetime, il s'agit également probablement d'une dépendance pour un grand nombre d'autres bibliothèques standard. L'instruction import coûterait alors très peu puisque l'initialisation du module se serait déjà produite. À ce stade, il ne fait que lier l'objet module existant à la portée locale.

Associez ces informations à l'argument de la lisibilité et je dirais qu'il est préférable d'avoir l'instruction import à la portée du module.

Jeremy Brown
la source
4

Juste pour compléter la réponse de Moe et la question d'origine:

Lorsque nous devons gérer des dépendances circulaires, nous pouvons faire quelques "trucs". En supposant que nous travaillons avec des modules a.pyet b.pyqui contiennent x()et b y(), respectivement. Alors:

  1. Nous pouvons déplacer l'un des from imports en bas du module.
  2. Nous pouvons déplacer l'un des from imports fonctions ou méthodes à intérieur qui nécessitent réellement l'importation (ce n'est pas toujours possible, car vous pouvez l'utiliser à plusieurs endroits).
  3. Nous pouvons changer l'un des deux from importspour être une importation qui ressemble à:import a

Donc, pour conclure. Si vous ne traitez pas des dépendances circulaires et ne faites pas une sorte d'astuce pour les éviter, alors il est préférable de placer toutes vos importations en haut pour les raisons déjà expliquées dans d'autres réponses à cette question. Et s'il vous plaît, lorsque vous faites ces "trucs" avec un commentaire, c'est toujours le bienvenu! :)

Caumons
la source
4

Outre les excellentes réponses déjà données, il convient de noter que le placement des importations n'est pas simplement 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 SparkContext avant d'importer des packages ou modules pyspark. Il est préférable de placer les importations pyspark dans une étendue où le SparkContext est garanti d'être disponible.

Paul
la source
4

J'ai été surpris de ne pas voir les chiffres des coûts réels pour les contrôles de charge répétés déjà publiés, bien qu'il existe de nombreuses bonnes explications sur ce à quoi s'attendre.

Si vous importez en haut, vous prenez la charge de charge quoi qu'il arrive. C'est assez petit, mais généralement en millisecondes, pas en nanosecondes.

Si vous importez dans une ou plusieurs fonctions, vous ne prenez le coup pour le chargement que si et quand une de ces fonctions est appelée pour la première fois. Comme beaucoup l'ont souligné, si cela ne se produit pas du tout, vous économisez le temps de chargement. Mais si la ou les fonctions sont souvent appelées, vous prenez un coup répété mais beaucoup plus petit (pour vérifier qu'elle a été chargée; pas pour le recharger réellement). D'autre part, comme l'a souligné @aaronasterling, vous économisez également un peu car l'importation dans une fonction permet à la fonction d'utiliser des recherches de variables locales légèrement plus rapides pour identifier le nom plus tard ( http://stackoverflow.com/questions/477096/python- import-coding-style / 4789963 # 4789963 ).

Voici les résultats d'un test simple qui importe quelques éléments de l'intérieur d'une fonction. Les temps signalés (en Python 2.7.14 sur un Intel Core i7 à 2,3 GHz) sont indiqués ci-dessous (le deuxième appel prenant plus que les appels ultérieurs semble cohérent, mais je ne sais pas pourquoi).

 0 foo:   14429.0924 µs
 1 foo:      63.8962 µs
 2 foo:      10.0136 µs
 3 foo:       7.1526 µs
 4 foo:       7.8678 µs
 0 bar:       9.0599 µs
 1 bar:       6.9141 µs
 2 bar:       7.1526 µs
 3 bar:       7.8678 µs
 4 bar:       7.1526 µs

Le code:

from __future__ import print_function
from time import time

def foo():
    import collections
    import re
    import string
    import math
    import subprocess
    return

def bar():
    import collections
    import re
    import string
    import math
    import subprocess
    return

t0 = time()
for i in xrange(5):
    foo()
    t1 = time()
    print("    %2d foo: %12.4f \xC2\xB5s" % (i, (t1-t0)*1E6))
    t0 = t1
for i in xrange(5):
    bar()
    t1 = time()
    print("    %2d bar: %12.4f \xC2\xB5s" % (i, (t1-t0)*1E6))
    t0 = t1
TextGeek
la source
Les changements dans l'exécution sont probablement dus à la mise à l'échelle de la fréquence du processeur en réponse à la charge. Il est préférable de démarrer les tests de vitesse avec une seconde de travail occupé pour augmenter la vitesse d'horloge du processeur.
Han-Kwang Nienhuys
3

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

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

VK
la source
3

Il est intéressant de noter qu'aucune réponse n'a mentionné le traitement parallèle jusqu'à présent, où il peut être REQUIS que les importations soient dans la fonction, lorsque le code de fonction sérialisé est ce qui est poussé vers d'autres cœurs, par exemple comme dans le cas d'ipyparallel.

K.-Michael Aye
la source
1

Il peut y avoir un gain de performances en important des variables / portée locale à l'intérieur d'une fonction. Cela dépend de l'utilisation de la chose importée dans la fonction. Si vous bouclez plusieurs fois et accédez à un objet global de module, l'importer en tant que local peut vous aider.

test.py

X=10
Y=11
Z=12
def add(i):
  i = i + 10

runlocal.py

from test import add, X, Y, Z

    def callme():
      x=X
      y=Y
      z=Z
      ladd=add 
      for i  in range(100000000):
        ladd(i)
        x+y+z

    callme()

run.py

from test import add, X, Y, Z

def callme():
  for i in range(100000000):
    add(i)
    X+Y+Z

callme()

Un temps sous Linux montre un petit gain

/usr/bin/time -f "\t%E real,\t%U user,\t%S sys" python run.py 
    0:17.80 real,   17.77 user, 0.01 sys
/tmp/test$ /usr/bin/time -f "\t%E real,\t%U user,\t%S sys" python runlocal.py 
    0:14.23 real,   14.22 user, 0.01 sys

réel est horloge murale. l'utilisateur est temps dans le programme. sys est temps pour les appels système.

https://docs.python.org/3.5/reference/executionmodel.html#resolution-of-names

pingouin tranquille
la source
1

Lisibilité

En plus des performances de démarrage, il y a un argument de lisibilité à faire pour localiser les importinstructions. Par exemple, prenez les numéros de ligne python 1283 à 1296 dans mon premier projet python actuel:

listdata.append(['tk font version', font_version])
listdata.append(['Gtk version', str(Gtk.get_major_version())+"."+
                 str(Gtk.get_minor_version())+"."+
                 str(Gtk.get_micro_version())])

import xml.etree.ElementTree as ET

xmltree = ET.parse('/usr/share/gnome/gnome-version.xml')
xmlroot = xmltree.getroot()
result = []
for child in xmlroot:
    result.append(child.text)
listdata.append(['Gnome version', result[0]+"."+result[1]+"."+
                 result[2]+" "+result[3]])

Si la importdéclaration était en haut du fichier, je devrais faire défiler vers le haut, ou appuyer sur Home, pour savoir ce qui ETétait. Ensuite, je devrais revenir à la ligne 1283 pour continuer à lire le code.

En effet, même si l' importinstruction était au sommet de la fonction (ou de la classe) comme beaucoup la placeraient, une pagination vers le haut et vers le bas serait nécessaire.

L'affichage du numéro de version de Gnome sera rarement fait, donc le importdébut du fichier introduit un retard de démarrage inutile.

WinEunuuchs2Unix
la source
0

Je voudrais mentionner un de mes cas d'utilisation, très similaire à ceux mentionnés par @John Millikin et @VK:

Importations facultatives

Je fais l'analyse des données avec Jupyter Notebook, et j'utilise le même bloc-notes IPython comme modèle pour toutes les analyses. Dans certains cas, j'ai besoin d'importer Tensorflow pour effectuer des exécutions de modèle rapides, mais parfois je travaille dans des endroits où tensorflow n'est pas configuré / est lent à importer. Dans ces cas, j'encapsule mes opérations dépendantes de Tensorflow dans une fonction d'assistance, j'importe Tensorflow à l'intérieur de cette fonction et je la lie à un bouton.

De cette façon, je pouvais faire "redémarrer et exécuter tout" sans avoir à attendre l'importation, ni à reprendre le reste des cellules en cas d'échec.

Cèdre
la source
0

Ceci est une discussion fascinante. Comme beaucoup d'autres, je n'avais même jamais envisagé ce sujet. J'ai été acculé à devoir avoir les importations dans les fonctions à cause de vouloir utiliser Django ORM dans une de mes bibliothèques. Je devais appeler django.setup()avant d'importer mes classes de modèle et parce que c'était en haut du fichier, il était glissé dans du code de bibliothèque complètement non Django en raison de la construction de l'injecteur IoC.

J'ai en quelque sorte piraté un peu et j'ai fini par mettre le django.setup()constructeur singleton et l'importation pertinente en haut de chaque méthode de classe. Maintenant, cela a bien fonctionné, mais cela m'a mis mal à l'aise parce que les importations n'étaient pas au sommet et j'ai également commencé à m'inquiéter du délai supplémentaire des importations. Ensuite, je suis venu ici et j'ai lu avec beaucoup d'intérêt tout le monde à ce sujet.

J'ai une longue expérience en C ++ et j'utilise maintenant Python / Cython. Mon point de vue est que pourquoi ne pas mettre les importations dans la fonction à moins que cela ne vous cause un goulot d'étranglement profilé. C'est comme déclarer de l'espace pour les variables juste avant d'en avoir besoin. Le problème est que j'ai des milliers de lignes de code avec toutes les importations en haut! Je pense donc que je vais le faire à partir de maintenant et changer le fichier impair ici et là quand je passerai et que j'aurai le temps.

LJHW
la source