web-dev-qa-db-fra.com

Quelles sont les bonnes règles de base pour les importations Python?

Je suis un peu confus par la multitude de façons dont vous pouvez importer des modules en Python.

import X
import X as Y
from A import B

J'ai lu des informations sur la portée et les espaces de noms, mais j'aimerais avoir des conseils pratiques sur la meilleure stratégie, dans quelles circonstances et pourquoi. Les importations doivent-elles se produire au niveau du module ou au niveau de la méthode/fonction? Dans le __init__.py ou dans le code du module lui-même?

Ma question n'est pas vraiment répondue par " packages Python - importation par classe, pas fichier " bien qu'elle soit évidemment liée.

71
Simon

Dans le code de production de notre entreprise, nous essayons de suivre les règles suivantes.

Nous plaçons les importations au début du fichier, juste après la docstring du fichier principal, par exemple:

"""
Registry related functionality.
"""
import wx
# ...

Maintenant, si nous importons une classe qui est l'une des rares dans le module importé, nous importons directement le nom, de sorte que dans le code, nous n'avons qu'à utiliser la dernière partie, par exemple:

from RegistryController import RegistryController
from ui.windows.lists import ListCtrl, DynamicListCtrl

Il existe cependant des modules qui contiennent des dizaines de classes, par exemple liste de toutes les exceptions possibles. Ensuite, nous importons le module lui-même et y faisons référence dans le code:

from main.core import Exceptions
# ...
raise Exceptions.FileNotFound()

Nous utilisons le import X as Y aussi rarement que possible, car cela rend difficile la recherche de l'utilisation d'un module ou d'une classe en particulier. Parfois, cependant, vous devez l'utiliser si vous souhaitez importer deux classes qui portent le même nom, mais existent dans différents modules, par exemple:

from Queue import Queue
from main.core.MessageQueue import Queue as MessageQueue

En règle générale, nous n'effectuons pas d'importations à l'intérieur des méthodes - elles rendent simplement le code plus lent et moins lisible. Certains peuvent trouver cela un bon moyen de résoudre facilement le problème des importations cycliques, mais une meilleure solution est la réorganisation du code.

64
DzinX

Permettez-moi de coller une partie de la conversation sur la liste de diffusion Django-dev commencée par Guido van Rossum:

[...] Par exemple, cela fait partie des guides de style Google Python [1] que toutes les importations doivent importer un module, pas une classe ou une fonction de ce module. Il y a bien plus de classes et les fonctions qu'il n'y a de modules, donc se rappeler d'où vient une chose particulière est beaucoup plus facile si elle est préfixée par un nom de module. Souvent, plusieurs modules définissent des choses avec le même nom - donc un lecteur de code n'a pas pour revenir en haut du fichier pour voir à partir de quel module un nom donné est importé.

Source: http://groups.google.com/group/Django-developers/browse_thread/thread/78975372cdfb7d1a

1: http://code.google.com/p/soc/wiki/PythonStyleGuide#Module_and_package_imports

35
Bartosz Ptaszynski

J'utiliserais normalement import X au niveau du module. Si vous n'avez besoin que d'un seul objet d'un module, utilisez from X import Y.

Seule utilisation import X as Y au cas où vous seriez autrement confronté à un conflit de noms.

J'utilise uniquement les importations au niveau de la fonction pour importer les éléments dont j'ai besoin lorsque le module est utilisé comme module principal, comme:

def main():
  import sys
  if len(sys.argv) > 1:
     pass

HTH

12
MvdD

Quelqu'un au-dessus a dit que

from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P

est équivalent à

import X

import X permet des modifications directes sur A-P, tandis que from X import ... crée des copies de A-P. Pour from X import A..P vous n'obtenez pas de mises à jour des variables si elles sont modifiées. Si vous les modifiez, vous ne modifiez que votre copie, mais X est au courant de vos modifications.

Si A-P sont des fonctions, vous ne saurez pas la différence.

9
Robert Jacobs

D'autres ont couvert la majeure partie du terrain ici, mais je voulais juste ajouter un cas où j'utiliserai import X as Y (temporairement), lorsque j'essaie une nouvelle version d'une classe ou d'un module.

Donc, si nous migrions vers une nouvelle implémentation d'un module, mais que nous ne voulions pas couper la base de code en une seule fois, nous pourrions écrire un xyz_new module et faites-le dans les fichiers sources que nous avons migrés:

import xyz_new as xyz

Ensuite, une fois que nous avons coupé toute la base de code, nous remplaçons simplement le module xyz par xyz_new et redéfinissez toutes les importations sur

import xyz
5
davidavr

NE FAITES PAS:

from X import *

sauf si vous êtes absolument sûr que vous utiliserez tout et n'importe quoi dans ce module. Et même alors, vous devriez probablement reconsidérer l'utilisation d'une approche différente.

A part ça, c'est juste une question de style.

from X import Y

est bon et vous permet d'économiser beaucoup de frappe. J'ai tendance à l'utiliser lorsque j'utilise quelque chose assez fréquemment, mais si vous importez beaucoup à partir de ce module, vous pouvez vous retrouver avec une instruction d'importation qui ressemble à ceci:

from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P

Vous avez eu l'idée. C'est alors que les importations comme

import X

devenir utile. Soit ça, soit si je n'utilise vraiment rien dans X très fréquemment.

3
Jason Baker

J'essaie généralement d'utiliser le import modulename Normal, à moins que le nom du module soit long ou utilisé souvent ..

Par exemple, je ferais ..

from BeautifulSoup import BeautifulStoneSoup as BSS

.. donc je peux faire soup = BSS(html) au lieu de BeautifulSoup.BeautifulStoneSoup(html)

Ou..

from xmpp import XmppClientBase

..au lieu d'importer l'intégralité de xmpp lorsque j'utilise uniquement XmppClientBase

L'utilisation de import x as y Est pratique si vous souhaitez importer des noms de méthode très longs, ou pour empêcher d'altérer une importation/variable/classe/méthode existante (ce que vous devriez essayer d'éviter complètement, mais ce n'est pas toujours possible)

Disons que je veux exécuter une fonction main () à partir d'un autre script, mais j'ai déjà une fonction main () ..

from my_other_module import main as other_module_main

..ne remplacerait pas ma fonction main par main de mon_autre_module

Oh, une chose - ne faites pas from x import * - cela rend votre code très difficile à comprendre, car vous ne pouvez pas facilement voir d'où vient une méthode (from x import *; from y import *; my_func() - où est défini mon_func?)

Dans tous les cas, vous pourriez faire simplement import modulename Puis faire modulename.subthing1.subthing2.method("test")...

Le truc from x import y as z Est purement pour la commodité - utilisez-le chaque fois que cela rendra votre code plus facile à lire ou à écrire!

2
dbr

Lorsque vous avez une bibliothèque bien écrite, ce qui est parfois le cas en python, vous devez simplement l'importer et l'utiliser comme elle. Une bibliothèque bien écrite a tendance à prendre vie et langue, ce qui donne un code agréable à lire, où vous faites rarement référence à la bibliothèque. Lorsqu'une bibliothèque est bien écrite, vous ne devriez pas avoir besoin de renommer ou autre chose trop souvent.

import gat

node = gat.Node()
child = node.children()

Parfois, il n'est pas possible de l'écrire de cette façon, ou alors vous voulez retirer des éléments de la bibliothèque que vous avez importée.

from gat import Node, SubNode

node = Node()
child = SubNode(node)

Parfois, vous faites cela pour beaucoup de choses, si votre chaîne d'importation dépasse 80 colonnes, c'est une bonne idée de le faire:

from gat import (
    Node, SubNode, TopNode, SuperNode, CoolNode,
    PowerNode, UpNode
)

La meilleure stratégie consiste à conserver toutes ces importations en haut du fichier. De préférence, classés par ordre alphabétique, importez d'abord les instructions, puis importez les instructions.

Maintenant, je vous dis pourquoi c'est la meilleure convention.

Python aurait parfaitement pu avoir une importation automatique, qui chercherait à partir des importations principales la valeur lorsqu'elle ne peut pas être trouvée à partir de l'espace de noms global. Mais ce n'est pas une bonne idée. J'explique brièvement pourquoi. En plus d'être plus compliqué à mettre en œuvre qu'une simple importation, les programmeurs ne penseraient pas tellement aux dépendances et découvrir d'où vous avez importé les choses devrait être fait autrement que de simplement regarder les importations.

Le besoin de découvrir les dépendances est une des raisons pour lesquelles les gens détestent "de ... import *". Il existe cependant de mauvais exemples où vous devez le faire, par exemple opengl -wrappings.

Les définitions d'importation sont donc réellement utiles pour définir les dépendances du programme. C'est la façon dont vous devez les exploiter. À partir d'eux, vous pouvez rapidement vérifier d'où est importée une fonction étrange.

1
Cheery

Je suis avec Jason dans le fait de ne pas utiliser

from X import *

Mais dans mon cas (je ne suis pas un programmeur expert, donc mon code ne correspond pas trop bien au style de codage), je fais généralement dans mes programmes un fichier avec toutes les constantes comme la version du programme, les auteurs, les messages d'erreur et tout ça, donc le fichier n'est que des définitions, alors je fais l'importation

from const import *

Cela me fait gagner beaucoup de temps. Mais c'est le seul fichier qui a cette importation, et c'est parce que tout à l'intérieur de ce fichier ne sont que des déclarations de variables.

Faire ce genre d'importation dans un fichier avec des classes et des définitions peut être utile, mais lorsque vous devez lire ce code, vous passez beaucoup de temps à localiser les fonctions et les classes.

0
Oscar Carballal

Le import X as Y Est utile si vous avez différentes implémentations du même module/classe.

Avec certains try..import..except ImportError..import Imbriqués, vous pouvez masquer l'implémentation de votre code. Voir exemple d'importation lxml etree :

try:
  from lxml import etree
  print("running with lxml.etree")
except ImportError:
  try:
    # Python 2.5
    import xml.etree.cElementTree as etree
    print("running with cElementTree on Python 2.5+")
  except ImportError:
    try:
      # Python 2.5
      import xml.etree.ElementTree as etree
      print("running with ElementTree on Python 2.5+")
    except ImportError:
      try:
        # normal cElementTree install
        import cElementTree as etree
        print("running with cElementTree")
      except ImportError:
        try:
          # normal ElementTree install
          import elementtree.ElementTree as etree
          print("running with ElementTree")
        except ImportError:
          print("Failed to import ElementTree from any known place")
0
olt