Então, estou recebendo este erro
Traceback (most recent call last):
File "/Users/alex/dev/runswift/utils/sim2014/simulator.py", line 3, in <module>
from world import World
File "/Users/alex/dev/runswift/utils/sim2014/world.py", line 2, in <module>
from entities.field import Field
File "/Users/alex/dev/runswift/utils/sim2014/entities/field.py", line 2, in <module>
from entities.goal import Goal
File "/Users/alex/dev/runswift/utils/sim2014/entities/goal.py", line 2, in <module>
from entities.post import Post
File "/Users/alex/dev/runswift/utils/sim2014/entities/post.py", line 4, in <module>
from physics import PostBody
File "/Users/alex/dev/runswift/utils/sim2014/physics.py", line 21, in <module>
from entities.post import Post
ImportError: cannot import name Post
e você pode ver que eu uso a mesma instrução de importação mais acima e funciona? Existe alguma regra não escrita sobre a importação circular? Como faço para usar a mesma classe mais abaixo na pilha de chamadas?
fonte
from
sintaxe sempre funcionará. Se eu tiverclass A(object): pass; class C(b.B): pass
no módulo a eclass B(a.A): pass
no módulo b, a importação circular ainda é um problema e não funcionará.B
para o móduloa
ou mova a classeC
para o módulob
para quebrar o ciclo. Também é importante notar que mesmo se apenas uma direção do círculo tiver código de nível superior envolvido (por exemplo, se a classeC
não existir), você pode obter um erro, dependendo de qual módulo foi importado primeiro por outro código.from . import sibling_module
, nãofrom .sibling_module import SomeClass
). Há um pouco mais de sutileza quando o__init__.py
arquivo de um pacote está envolvido na importação circular, mas o problema é raro e provavelmente um bug naimport
implementação. Veja o bug 23447 do Python , para o qual enviei um patch (que infelizmente está enfraquecendo).Quando você importa um módulo (ou um membro dele) pela primeira vez, o código dentro do módulo é executado sequencialmente como qualquer outro código; por exemplo, não é tratado de forma diferente que o corpo de uma função. Um
import
é apenas um comando como qualquer outro (atribuição, uma chamada de função,def
,class
). Supondo que suas importações ocorram no início do script, eis o que está acontecendo:World
deworld
, oworld
script é executado.world
script é importadoField
, o que faz com que oentities.field
script seja executado.entities.post
script porque tentou importarPost
entities.post
script faz com que ophysics
módulo seja executado porque ele tenta importarPostBody
physics
tenta importarPost
deentities.post
entities.post
módulo existe na memória ainda, mas realmente não importa. Ou o módulo não está na memória, ou o módulo ainda não tem umPost
membro porque não terminou de executar para definirPost
Post
não existe para ser importadoPortanto, não, não está "avançando na pilha de chamadas". Este é um rastreamento de pilha de onde ocorreu o erro, o que significa que houve um erro ao tentar importar
Post
nessa classe. Você não deve usar importações circulares. Na melhor das hipóteses, ele tem um benefício insignificante (normalmente, nenhum benefício) e causa problemas como esse. Ele onera qualquer desenvolvedor que o mantenha, forçando-o a pisar na casca do ovo para evitar quebrá-lo. Refatore sua organização de módulo.fonte
isinstance(userData, Post)
. Independentemente disso, você não tem escolha. A importação circular não funcionará. O fato de você ter importações circulares é um cheiro de código para mim. Isso sugere que você tem alguma funcionalidade que deve ser transferida para um terceiro módulo. Eu não poderia dizer o quê sem olhar para as duas classes inteiras.def
não é executado até que a função seja chamada, portanto, a importação não ocorreria até que você realmente chamasse a função. Nesse momento, osimport
s devem funcionar, pois um dos módulos teria sido completamente importado antes da chamada. Esse é um hack absolutamente nojento e não deve permanecer em sua base de código por um período de tempo significativo.import foo
vez defrom foo import Bar
. Isso porque a maioria dos módulos apenas define coisas (como funções e classes) que são executadas posteriormente. Módulos que fazem coisas significativas quando você os importa (como um script não protegido porif __name__ == "__main__"
) ainda podem ser problemas, mas isso não é muito comum.Para entender as dependências circulares, você precisa se lembrar de que Python é essencialmente uma linguagem de script. A execução de instruções fora dos métodos ocorre em tempo de compilação. As instruções de importação são executadas como chamadas de método e, para compreendê-las, você deve pensar nelas como chamadas de método.
Quando você faz uma importação, o que acontece depende se o arquivo que você está importando já existe na tabela do módulo. Em caso afirmativo, Python usa tudo o que está atualmente na tabela de símbolos. Caso contrário, o Python começa a ler o arquivo do módulo, compilando / executando / importando tudo o que encontrar lá. Os símbolos referenciados em tempo de compilação são encontrados ou não, dependendo se eles foram vistos ou ainda não foram vistos pelo compilador.
Imagine que você tenha dois arquivos de origem:
Arquivo X.py
Arquivo Y.py
Agora, suponha que você compile o arquivo X.py. O compilador começa definindo o método X1 e, em seguida, acessa a instrução import em X.py. Isso faz com que o compilador pause a compilação de X.py e comece a compilar Y.py. Pouco depois, o compilador acessa a instrução import em Y.py. Como o X.py já está na tabela do módulo, o Python usa a tabela de símbolos X.py incompleta existente para satisfazer todas as referências solicitadas. Todos os símbolos que aparecem antes da instrução de importação em X.py agora estão na tabela de símbolos, mas os símbolos posteriores não estão. Como X1 agora aparece antes da instrução de importação, ele foi importado com sucesso. O Python então retoma a compilação de Y.py. Ao fazer isso, ele define Y2 e termina de compilar Y.py. Em seguida, ele retoma a compilação de X.py e encontra Y2 na tabela de símbolos Y.py. A compilação eventualmente termina sem erro.
Algo muito diferente acontece se você tentar compilar Y.py a partir da linha de comando. Ao compilar Y.py, o compilador acessa a instrução import antes de definir Y2. Em seguida, ele começa a compilar o X.py. Logo ele atinge a instrução import em X.py que requer Y2. Mas Y2 é indefinido, então a compilação falha.
Observe que se você modificar o X.py para importar Y1, a compilação sempre será bem-sucedida, independentemente do arquivo que você compilar. No entanto, se você modificar o arquivo Y.py para importar o símbolo X2, nenhum arquivo será compilado.
Sempre que o módulo X ou qualquer módulo importado pelo X puder importar o módulo atual, NÃO use:
Sempre que você achar que pode haver uma importação circular, você também deve evitar referências em tempo de compilação a variáveis em outros módulos. Considere o código de aparência inocente:
Suponha que o módulo X importe este módulo antes que este módulo importe X. Além disso, suponha que Y seja definido em X após a instrução de importação. Então, Y não será definido quando este módulo for importado e você obterá um erro de compilação. Se este módulo importar Y primeiro, você pode se safar. Mas quando um de seus colegas de trabalho muda inocentemente a ordem das definições em um terceiro módulo, o código falha.
Em alguns casos, você pode resolver dependências circulares movendo uma instrução de importação para baixo, abaixo das definições de símbolo necessárias para outros módulos. Nos exemplos acima, as definições antes da instrução import nunca falham. As definições após a instrução de importação às vezes falham, dependendo da ordem de compilação. Você pode até colocar instruções de importação no final de um arquivo, desde que nenhum dos símbolos importados seja necessário no momento da compilação.
Observe que mover as instruções de importação para baixo em um módulo obscurece o que você está fazendo. Compense isso com um comentário no topo do seu módulo, algo como o seguinte:
Em geral, essa é uma prática ruim, mas às vezes é difícil de evitar.
fonte
Para aqueles de vocês que, como eu, chegaram a este problema do Django, devem saber que os documentos fornecem uma solução: https://docs.djangoproject.com/en/1.10/ref/models/fields/#foreignkey
"... Para referir-se a modelos definidos em outro aplicativo, você pode especificar explicitamente um modelo com o rótulo completo do aplicativo. Por exemplo, se o modelo do fabricante acima for definido em outro aplicativo chamado produção, você precisará usar:
Esse tipo de referência pode ser útil ao resolver dependências de importação circular entre dois aplicativos. ... "
fonte
Consegui importar o módulo dentro da função (apenas) que exigiria os objetos deste módulo:
fonte
Se você encontrar esse problema em um aplicativo bastante complexo, pode ser complicado refatorar todas as suas importações. O PyCharm oferece uma correção rápida para isso, que também altera automaticamente todo o uso dos símbolos importados.
fonte
Eu estava usando o seguinte:
mas para me livrar
circular reference
fiz o seguinte e funcionou:fonte