Como importar classes definidas em __init__.py

105

Estou tentando organizar alguns módulos para meu próprio uso. Eu tenho algo assim:

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

Em lib/__init__.py, desejo definir algumas classes a serem usadas se eu importar lib. No entanto, não consigo descobrir isso sem separar as classes em arquivos e importá-los __init__.py.

Em vez de dizer:

    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

Eu quero algo assim:

    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

É possível ou tenho que separar a classe em outro arquivo?

EDITAR

OK, se eu importar lib de outro script, posso acessar a classe Helper. Como posso acessar a classe Helper em settings.py?

O exemplo aqui descreve referências dentro do pacote. Cito "os submódulos geralmente precisam se referir uns aos outros". No meu caso, o lib.settings.py precisa do Helper e lib.foo.someobject precisa de acesso ao Helper, então onde devo definir a classe Helper?

Scottm
fonte
Seu último exemplo deve funcionar. Você está vendo um ImportError? Você pode colar os detalhes?
Joe Holloway

Respostas:

81
  1. o lib/diretório pai de deve estar em sys.path.

  2. Seu ' lib/__init__.py' pode ser assim:

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

Então, o seguinte exemplo deve funcionar:

from lib.settings import Values
from lib import Helper

Resposta à versão editada da pergunta:

__init__.pydefine a aparência de seu pacote de fora. Se precisar usar Helperem settings.py, defina Helperem um arquivo diferente, por exemplo, ' lib/helper.py'.

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

2 diretórios, 6 arquivos

O comando:

$ python import_submodule.py

Resultado:

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
fonte
Como eu poderia importar a classe Helper no arquivo settings.py em meu exemplo?
scottm
Não entendo por que isso é circular. Se settings.py precisa do Helper e diz foo.someobject.py precisa do Helper, onde você sugere que eu o defina?
scottm
uau, a palavra "ajudante" realmente começa a perder significado naquele exemplo. No entanto, você me mostrou o que eu estava procurando.
scottm
3
upvoted para "__init__.py define a aparência do seu pacote de fora."
Petri
19

Se lib/__init__.pydefine a classe Helper, em settings.py você pode usar:

from . import Helper

Isso funciona porque. é o diretório atual e atua como um sinônimo para o pacote lib do ponto de vista do módulo de configurações. Observe que não é necessário exportar o Helper via __all__.

(Confirmado com python 2.7.10, em execução no Windows.)

yoyo
fonte
1
Isso está funcionando bem para mim, downvoters, por favor, expliquem seu descontentamento?
yoyo
8

Você acabou de colocá-los em __init__.py.

Portanto, com test / classes.py sendo:

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

... e test / __ init__.py sendo:

from classes import *

class Helper(object): pass

Você pode importar teste e ter acesso a A, B e Helper

>>> import test
>>> test.A
<class 'test.classes.A'>
>>> test.B
<class 'test.classes.B'>
>>> test.Helper
<class 'test.Helper'>
Aaron Maenpaa
fonte
De onde você está fazendo a importação?
Aaron Maenpaa
Digamos que eu queira importar o Helper de lib / settings.py?
scottm
1
Isso quase certamente resultará em uma importação circular (as configurações importarão o teste e o teste importará as configurações) ... que produzirá o NameError que você descreve. Se você deseja auxiliares que são usados ​​dentro do pacote, você deve definir um módulo interno que seu código usa.
Aaron Maenpaa
1
Os ajudantes em init .py devem ser para usuários externos para simplificar sua API.
Aaron Maenpaa
1
Se não faz parte da API, init .py realmente não é o lugar para isso. lib / internal.py ou similar seria muito melhor (que tem o duplo propósito de reduzir a probabilidade de importações circulares).
Aaron Maenpaa
5

Adicione algo assim a lib/__init__.py

from .helperclass import Helper

agora você pode importá-lo diretamente:

from lib import Helper

Dawid Gosławski
fonte
4

Edite, uma vez que não entendi bem a questão:

Basta colocar a Helperclasse __init__.py. Isso é perfeitamente pitônico. Parece estranho vindo de linguagens como Java.

Richard Levasseur
fonte
Você entendeu mal. Desejo eliminar o arquivo helperClass.py, se possível.
scottm
Richard não é o único que entendeu mal. Seu exemplo deve estar funcionando. Qual é o traceback?
Troy J. Farrell
Bem, então eu li os documentos corretamente. Então, acabei de fazer um caso de teste e funciona bem.
scottm
Eu tenho a mesma configuração em meu pacote, mas estou recebendo um ImportError "não é possível importar nome do Helper"
scottm
Acho que meu problema é que estou tentando importar a classe Helper de settings.py, como posso fazer isso?
scottm
2

Sim, é possível. Você também pode querer definir __all__em __init__.pyarquivos. É uma lista de módulos que serão importados quando você fizer

from lib import *
Vartec
fonte
-6

Talvez isso pudesse funcionar:

import __init__ as lib
Turion
fonte