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?


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

¿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).


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'>

¿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


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.


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 *

-6

Quizás esto podría funcionar:

import __init__ as lib
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.