Comment importer des classes définies dans __init__.py


105

J'essaye d'organiser certains modules pour mon propre usage. J'ai quelque chose comme ça:

lib/
  __init__.py
  settings.py
  foo/
    __init__.py
    someobject.py
  bar/
    __init__.py
    somethingelse.py

Dans lib/__init__.py, je souhaite définir certaines classes à utiliser si j'importe lib. Cependant, je n'arrive pas à le comprendre sans séparer les classes en fichiers et les importer dans __init__.py.

Plutôt que de dire:

    lib/
      __init__.py
      settings.py
      helperclass.py
      foo/
        __init__.py
        someobject.py
      bar/
        __init__.py
        somethingelse.py

from lib.settings import Values
from lib.helperclass import Helper

Je veux quelque chose comme ça:

    lib/
      __init__.py  #Helper defined in this file
      settings.py
      foo/
        __init__.py
        someobject.py
      bar/
        __init__.py
        somethingelse.py

from lib.settings import Values
from lib import Helper

Est-ce possible ou dois-je séparer la classe dans un autre fichier?

ÉDITER

OK, si j'importe la lib depuis un autre script, je peux accéder à la classe Helper. Comment puis-je accéder à la classe Helper à partir de settings.py?

L'exemple décrit ici décrit les références intra-package. Je cite "les sous-modules doivent souvent se référer les uns aux autres". Dans mon cas, lib.settings.py a besoin du Helper et lib.foo.someobject doit avoir accès à Helper, alors où dois-je définir la classe Helper?


Votre dernier exemple devrait fonctionner. Voyez-vous une erreur ImportError? Pouvez-vous coller les détails?
Joe Holloway

Réponses:


81
  1. Le lib/répertoire parent de 'doit être dans sys.path.

  2. Votre " lib/__init__.py" pourrait ressembler à ceci:

    from . import settings # or just 'import settings' on old Python versions
    class Helper(object):
          pass

Ensuite, l'exemple suivant devrait fonctionner:

from lib.settings import Values
from lib import Helper

Réponse à la version modifiée de la question:

__init__.pydéfinit l'apparence de votre colis de l'extérieur. Si vous devez utiliser Helperdans, settings.pydéfinissez-le Helperdans un fichier différent, par exemple, « lib/helper.py».

.
| `- import_submodule.py
    `- lib
    | - __init__.py
    | - toto
    | | - __init__.py
    | `- someobject.py
    | - helper.py
    `- settings.py

2 répertoires, 6 fichiers

La commande:

$ python import_submodule.py

Production:

settings
helper
Helper in lib.settings
someobject
Helper in lib.foo.someobject

# ./import_submodule.py
import fnmatch, os
from lib.settings import Values
from lib import Helper

print
for root, dirs, files in os.walk('.'):
    for f in fnmatch.filter(files, '*.py'):
        print "# %s/%s" % (os.path.basename(root), f)
        print open(os.path.join(root, f)).read()
        print


# lib/helper.py
print 'helper'
class Helper(object):
    def __init__(self, module_name):
        print "Helper in", module_name


# lib/settings.py
print "settings"
import helper

class Values(object):
    pass

helper.Helper(__name__)


# lib/__init__.py
#from __future__ import absolute_import
import settings, foo.someobject, helper

Helper = helper.Helper


# foo/someobject.py
print "someobject"
from .. import helper

helper.Helper(__name__)


# foo/__init__.py
import someobject

Comment puis-je importer la classe Helper dans le fichier settings.py de mon exemple?
scottm

Je ne comprends pas pourquoi c'est circulaire. Si settings.py a besoin de Helper et que foo.someobject.py a besoin de Helper, où suggérez-vous de le définir?
scottm

wow, le mot «aide» commence vraiment à perdre son sens dans cet exemple. Cependant, vous m'avez montré ce que je cherchais.
scottm

3
voté pour "__init__.py définit l'apparence de votre package de l'extérieur."
Petri

19

Si lib/__init__.pydéfinit la classe Helper, dans settings.py, vous pouvez utiliser:

from . import Helper

Cela fonctionne parce que. est le répertoire courant, et agit comme synonyme du paquet lib du point de vue du module de paramètres. Notez qu'il n'est pas nécessaire d'exporter Helper via __all__.

(Confirmé avec python 2.7.10, fonctionnant sous Windows.)


1
Cela fonctionne bien pour moi, les votants négatifs, veuillez expliquer votre mécontentement?
yoyo du

8

Vous venez de les mettre dans __init__.py.

Donc, avec test / classes.py étant:

class A(object): pass
class B(object): pass

... et test / __ init__.py étant:

from classes import *

class Helper(object): pass

Vous pouvez importer le test et avoir accès à A, B et Helper

>>> import test
>>> test.A
<class 'test.classes.A'>
>>> test.B
<class 'test.classes.B'>
>>> test.Helper
<class 'test.Helper'>

D'où faites-vous l'importation?
Aaron Maenpaa

Dire que je veux importer Helper depuis lib / settings.py?
scottm

1
Cela entraînera presque certainement une importation circulaire (les paramètres importeront le test et le test importera les paramètres) ... qui produira le NameError que vous décrivez. Si vous voulez des helpers qui sont utilisés dans le package, vous devez définir un module interne que votre code utilise.
Aaron Maenpaa

1
Les helpers dans init .py doivent être destinés aux utilisateurs externes afin de simplifier votre API.
Aaron Maenpaa

1
Si cela ne fait pas partie de l'API, alors init .py n'est vraiment pas l'endroit idéal. lib / internal.py ou similaire serait bien meilleur (ce qui a le double objectif de réduire la probabilité d'importations circulaires).
Aaron Maenpaa

5

Ajoutez quelque chose comme ça à lib/__init__.py

from .helperclass import Helper

maintenant vous pouvez l'importer directement:

from lib import Helper


4

Edit, puisque j'ai mal compris la question:

Mettez simplement la Helperclasse dedans __init__.py. C'est parfaitement pythonique. Cela semble étrange venant de langages comme Java.


Tu as mal compris. Je veux éliminer le fichier helperClass.py si possible.
scottm

Richard n'est pas le seul à avoir mal compris. Votre exemple devrait fonctionner. Qu'est-ce que le retraçage?
Troy

Eh bien, j'ai lu correctement la documentation. Donc, maintenant, je viens de faire un cas de test et cela fonctionne bien.
scottm

J'ai la même configuration dans mon package, mais j'obtiens un ImportError "impossible d'importer le nom Helper"
scottm

Je pense que mon problème est que j'essaie d'importer la classe Helper à partir de settings.py, comment pourrais-je faire cela?
scottm

2

Oui c'est possible. Vous pouvez également vouloir définir __all__dans des __init__.pyfichiers. C'est une liste de modules qui seront importés lorsque vous le faites

from lib import *

-6

Peut-être que cela pourrait fonctionner:

import __init__ as lib
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.