Eu tenho uma estrutura de diretório semelhante à seguinte
meta_project
project1
__init__.py
lib
module.py
__init__.py
notebook_folder
notebook.jpynb
Ao trabalhar em notebook.jpynb
se tento usar uma importação relativa para acessar uma função function()
em module.py
com:
from ..project1.lib.module import function
Estou tendo o erro a seguir:
SystemError Traceback (most recent call last)
<ipython-input-7-6393744d93ab> in <module>()
----> 1 from ..project1.lib.module import function
SystemError: Parent module '' not loaded, cannot perform relative import
Existe alguma maneira de fazer isso funcionar usando importações relativas?
Observe que o servidor do notebook é instanciado no nível do meta_project
diretório, portanto, ele deve ter acesso às informações nesses arquivos.
Observe, também, que pelo menos como originalmente pretendido, project1
não foi pensado como um módulo e, portanto, não tem um __init__.py
arquivo, mas sim um diretório do sistema de arquivos. Se a solução para o problema requer tratá-lo como um módulo e incluir um __init__.py
arquivo (mesmo um em branco), tudo bem, mas fazer isso não é o suficiente para resolver o problema.
Eu compartilho este diretório entre máquinas e importações relativas me permitem usar o mesmo código em todos os lugares, e eu freqüentemente uso notebooks para prototipagem rápida, então sugestões que envolvem hackear caminhos absolutos provavelmente não serão úteis.
Editar: isso é diferente das importações relativas em Python 3 , que fala sobre importações relativas em Python 3 em geral e - em particular - a execução de um script de dentro de um diretório de pacote. Isso tem a ver com trabalhar dentro de um bloco de notas jupyter tentando chamar uma função em um módulo local em outro diretório que tem aspectos gerais e particulares diferentes.
__init__
arquivo no diretório do seu pacote?lib
diretório.Respostas:
Tive quase o mesmo exemplo que você neste notebook, em que queria ilustrar o uso da função de um módulo adjacente de maneira SECA.
Minha solução foi informar ao Python esse caminho de importação de módulo adicional adicionando um snippet como este ao bloco de notas:
Isso permite que você importe a função desejada da hierarquia do módulo:
Observe que é necessário adicionar
__init__.py
arquivos vazios às pastas project1 / e lib / se você ainda não os tiver.fonte
Vim aqui em busca de melhores práticas na abstração de código para submódulos ao trabalhar em Notebooks. Não tenho certeza se existe uma prática recomendada. Eu tenho proposto isso.
Uma hierarquia de projeto como:
E de
20170609-Initial_Database_Connection.ipynb
:Isso funciona porque, por padrão, o Jupyter Notebook pode analisar o
cd
comando. Observe que isso não faz uso da mágica do Python Notebook. Ele simplesmente funciona sem prefixar%bash
.Considerando que 99 em 100 vezes estou trabalhando no Docker usando uma das imagens do Docker do Projeto Jupyter , a seguinte modificação é idempotente
fonte
chdir
vez de adicionar ao caminho, já que estou interessado em importar do repositório principal e também em fazer a interface com alguns arquivos lá.if os.path.isdir('../lib/'): os.chdir('../lib')
:; ou, melhor, use../lib/db/
com seupostgres.py
para não acidentalmente mudar para um diretório superior que também contenha outrolib
.cd ..
duas vezes.Até agora, a resposta aceita funcionou melhor para mim. No entanto, minha preocupação sempre foi que há um cenário provável em que eu possa refatorar o
notebooks
diretório em subdiretórios, exigindo a alteraçãomodule_path
em cada bloco de notas. Decidi adicionar um arquivo python em cada diretório de notebook para importar os módulos necessários.Assim, possuindo a seguinte estrutura de projeto:
Eu adicionei o arquivo
project_path.py
em cada subdiretório de notebook (notebooks/explore
enotebooks/explain
). Este arquivo contém o código para importações relativas (de @metakermit):Dessa forma, eu só preciso fazer importações relativas dentro do
project_path.py
arquivo, e não nos blocos de notas. Os arquivos dos blocos de notas só precisariam ser importadosproject_path
antes da importaçãolib
. Por exemplo em0.0-notebook.ipynb
:A ressalva aqui é que reverter as importações não funcionaria. ISSO NÃO FUNCIONA:
Portanto, deve-se ter cuidado durante as importações.
fonte
Acabei de encontrar esta solução bonita:
Você só quer algumas funções desse arquivo
Se python version> = 3.3 você não precisa do arquivo init.py na pasta
fonte
if ".." not in sys.path: ... sys.path.insert(0,"..")
Pesquisando este tópico e tendo lido as respostas, recomendo usar a biblioteca path.py pois ela fornece um gerenciador de contexto para alterar o diretório de trabalho atual.
Você então tem algo como
Embora, você possa simplesmente omitir a
isdir
declaração.Aqui, adicionarei instruções de impressão para facilitar o acompanhamento do que está acontecendo
que resulta neste exemplo (onde lib está em
/home/jovyan/shared/notebooks/by-team/data-vis/demos/lib
):Visto que a solução usa um gerenciador de contexto, você tem a garantia de voltar ao seu diretório de trabalho anterior, não importa em que estado seu kernel estava antes da célula e não importa quais exceções são lançadas ao importar o código da sua biblioteca.
fonte
Aqui estão meus 2 centavos:
import sys
mapeie o caminho onde o arquivo do módulo está localizado. No meu caso foi o desktop
sys.path.append ('/ Users / John / Desktop')
Importe todo o módulo de mapeamento, MAS então você terá que usar o .notation para mapear as classes como mapping.Shipping ()
import mapping # mapping.py é o nome do meu arquivo de módulo
shipit = mapping.Shipment () #Shipment é o nome da classe que preciso usar no módulo de mapeamento
Ou importe a classe específica do módulo de mapeamento
de mapeamento importação Mapeamento
shipit = Shipment () #Agora você não precisa usar o .notation
fonte
Descobri que o python-dotenv ajuda a resolver esse problema de maneira bastante eficaz. A estrutura do seu projeto acaba mudando um pouco, mas o código em seu notebook é um pouco mais simples e consistente em todos os notebooks.
Para o seu projeto, instale um pouco.
Então, o projeto muda para:
E, finalmente, sua importação muda para:
Um +1 para este pacote é que seus blocos de notas podem ter vários diretórios de profundidade. python-dotenv encontrará o mais próximo em um diretório pai e o usará. Um +2 para essa abordagem é que o jupyter carregará as variáveis de ambiente do arquivo .env na inicialização. Golpe duplo.
fonte