Cómo importar clases definidas en __init__.py

105

Estoy intentando organizar algunos módulos para mi propio uso. Tengo algo como esto:

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

En lib/__init__.py, quiero definir algunas clases que se usarán si importo lib. Sin embargo, parece que no puedo resolverlo sin separar las clases en archivos e importarlos __init__.py.

En lugar de decir:

    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

Quiero algo como esto:

    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

¿Es posible o tengo que separar la clase en otro archivo?

EDITAR

OK, si importo lib desde otro script, puedo acceder a la clase Helper. ¿Cómo puedo acceder a la clase Helper desde settings.py?

El ejemplo aquí describe las referencias dentro del paquete. Cito "los submódulos a menudo necesitan referirse entre sí". En mi caso, lib.settings.py necesita el Helper y lib.foo.someobject necesita acceso al Helper, entonces, ¿dónde debería definir la clase Helper?

Scottm
fuente
Tu último ejemplo debería funcionar. ¿Está viendo un ImportError? ¿Puedes pegar los detalles?
Joe Holloway

Respuestas:

81
  1. ' lib/'S directorio principal debe estar en sys.path.

  2. Su ' lib/__init__.py' podría verse así:

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

Entonces el siguiente ejemplo debería funcionar:

from lib.settings import Values
from lib import Helper

Responda a la versión editada de la pregunta:

__init__.pydefine cómo se ve su paquete desde el exterior. Si necesita usar Helperen settings.py, defina Helperen un archivo diferente, por ejemplo, " lib/helper.py".

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

2 directorios, 6 archivos

El comando:

$ python import_submodule.py

Salida:

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
jfs
fuente
¿Cómo podría importar la clase Helper en el archivo settings.py en mi ejemplo?
scottm
No entiendo por qué eso es circular. Si settings.py necesita Helper y dice que foo.someobject.py necesita Helper, ¿dónde sugieres que lo defina?
scottm
Guau, la palabra "ayudante" realmente comienza a perder significado en ese ejemplo. Sin embargo, me ha mostrado lo que estaba buscando.
scottm
3
upvoted para "__init__.py define cómo se ve su paquete desde el exterior".
Petri
19

Si lib/__init__.pydefine la clase Helper, en settings.py puede usar:

from . import Helper

Esto funciona porque. es el directorio actual y actúa como sinónimo del paquete lib desde el punto de vista del módulo de configuración. Tenga en cuenta que no es necesario exportar Helper a través de __all__.

(Confirmado con python 2.7.10, que se ejecuta en Windows).

yoyó
fuente
1
Esto está funcionando bien para mí, votantes negativos, por favor expliquen su disgusto.
yoyo
8

Simplemente póngalos en __init__.py.

Entonces, con test / classes.py siendo:

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

... y prueba / __ init__.py siendo:

from classes import *

class Helper(object): pass

Puede importar la prueba y tener acceso a A, B y Helper

>>> import test
>>> test.A
<class 'test.classes.A'>
>>> test.B
<class 'test.classes.B'>
>>> test.Helper
<class 'test.Helper'>
Aaron Maenpaa
fuente
¿De dónde haces la importación?
Aaron Maenpaa
Digamos que quiero importar Helper desde lib / settings.py.
scottm
1
Es casi seguro que eso resultará en una importación circular (la configuración importará la prueba y la prueba importará la configuración) ... que producirá el NameError que describe. Si desea ayudantes que se utilizan dentro del paquete, debe definir un módulo interno que utiliza su código.
Aaron Maenpaa
1
Los ayudantes en init .py deben ser para usuarios externos para simplificar su API.
Aaron Maenpaa
1
Si no es parte de la API, entonces init .py realmente no es el lugar para ello. lib / internal.py o similar sería mucho mejor (que tiene el doble propósito de reducir la probabilidad de importaciones circulares).
Aaron Maenpaa
5

Agrega algo como esto a lib/__init__.py

from .helperclass import Helper

ahora puedes importarlo directamente:

from lib import Helper

Dawid Gosławski
fuente
4

Editar, ya que entendí mal la pregunta:

Solo ingresa la Helperclase __init__.py. Eso es perfectamente pitónico. Se siente extraño viniendo de lenguajes como Java.

Richard Levasseur
fuente
Has entendido mal. Quiero eliminar el archivo helperClass.py si es posible.
scottm
Richard no es el único que entendió mal. Tu ejemplo debería estar funcionando. ¿Qué es el rastreo?
Troy J. Farrell
Bueno, entonces leí los documentos correctamente. Entonces, ahora acabo de hacer un caso de prueba y funciona bien.
scottm
Tengo la misma configuración en mi paquete, pero obtengo un ImportError "no se puede importar el
asistente de
Creo que mi problema es que estoy tratando de importar la clase Helper desde settings.py, ¿cómo podría hacer eso?
scottm
2

Sí, es posible. Es posible que también desee definir __all__en __init__.pyarchivos. Es una lista de módulos que se importarán cuando lo haga

from lib import *
vartec
fuente
-6

Quizás esto podría funcionar:

import __init__ as lib
Turion
fuente