Script vs. Módulo
Aqui está uma explicação. A versão curta é que há uma grande diferença entre executar diretamente um arquivo Python e importá-lo de outro lugar. Apenas saber em que diretório um arquivo está não determina em que pacote o Python pensa que está. Isso depende, adicionalmente, de como você carrega o arquivo no Python (executando ou importando).
Existem duas maneiras de carregar um arquivo Python: como o script de nível superior ou como um módulo. Um arquivo é carregado como o script de nível superior se você o executar diretamente, por exemplo, digitando python myfile.py
na linha de comando. Ele é carregado como um módulo, se você o fizer python -m myfile
, ou se for carregado quando uma import
instrução for encontrada dentro de outro arquivo. Só pode haver um script de nível superior por vez; o script de nível superior é o arquivo Python que você executou para começar.
Nomeação
Quando um arquivo é carregado, ele recebe um nome (que é armazenado em seu __name__
atributo). Se ele foi carregado como o script de nível superior, seu nome é __main__
. Se ele foi carregado como um módulo, seu nome é o nome do arquivo, precedido pelos nomes de quaisquer pacotes / subpacotes dos quais faz parte, separados por pontos.
Por exemplo, no seu exemplo:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
se você importou moduleX
(nota: importado , não executado diretamente), seu nome seria package.subpackage1.moduleX
. Se você importasse moduleA
, seu nome seria package.moduleA
. No entanto, se você executar diretamente moduleX
na linha de comando, seu nome será __main__
e, se você executar diretamente moduleA
na linha de comando, o nome será __main__
. Quando um módulo é executado como o script de nível superior, ele perde seu nome normal e seu nome é __main__
.
Acessando um módulo NÃO através do pacote que o contém
Há uma ruga adicional: o nome do módulo depende se foi importado "diretamente" do diretório em que está ou se foi importado por meio de um pacote. Isso só faz diferença se você executar o Python em um diretório e tentar importar um arquivo no mesmo diretório (ou em um subdiretório). Por exemplo, se você iniciar o interpretador Python no diretório package/subpackage1
e o fizer import moduleX
, o nome de moduleX
apenas será moduleX
, e não package.subpackage1.moduleX
. Isso ocorre porque o Python adiciona o diretório atual ao seu caminho de pesquisa na inicialização; se encontrar o módulo a ser importado no diretório atual, ele não saberá que esse diretório faz parte de um pacote e as informações do pacote não se tornarão parte do nome do módulo.
Um caso especial é se você executar o interpretador interativamente (por exemplo, basta digitar python
e começar a digitar o código Python em tempo real). Nesse caso, o nome dessa sessão interativa é __main__
.
Agora, aqui está a coisa crucial para sua mensagem de erro: se o nome de um módulo não tiver pontos, ele não será considerado parte de um pacote . Não importa onde o arquivo está no disco. Tudo o que importa é qual é o nome e depende de como você o carregou.
Agora observe a citação que você incluiu na sua pergunta:
As importações relativas usam o atributo de nome de um módulo para determinar a posição desse módulo na hierarquia de pacotes. Se o nome do módulo não contiver nenhuma informação do pacote (por exemplo, está definido como 'main'), as importações relativas serão resolvidas como se o módulo fosse um módulo de nível superior, independentemente de onde o módulo esteja realmente localizado no sistema de arquivos.
Importações relativas ...
As importações relativas usam o nome do módulo para determinar onde ele está em um pacote. Quando você usa uma importação relativa como from .. import foo
, os pontos indicam para aumentar um número de níveis na hierarquia de pacotes. Por exemplo, se o nome do seu módulo atual for package.subpackage1.moduleX
, ..moduleA
isso significaria package.moduleA
. Para que um from .. import
trabalho funcione, o nome do módulo deve ter pelo menos quantos pontos houver na import
instrução.
... são apenas relativos em um pacote
No entanto, se o nome do seu módulo for __main__
, ele não será considerado em um pacote. Seu nome não tem pontos e, portanto, você não pode usar from .. import
instruções dentro dele. Se você tentar fazer isso, receberá o erro "importação relativa no pacote".
Os scripts não podem importar relativos
O que você provavelmente fez foi tentar executar algo moduleX
semelhante na linha de comando. Quando você fez isso, seu nome foi definido como __main__
, o que significa que as importações relativas falharão, porque seu nome não revela que está em um pacote. Observe que isso também acontecerá se você executar o Python a partir do mesmo diretório em que um módulo está e tentar importar esse módulo, porque, conforme descrito acima, o Python encontrará o módulo no diretório atual "muito cedo" sem perceber que é parte de um pacote.
Lembre-se também de que, quando você executa o intérprete interativo, o "nome" dessa sessão interativa é sempre __main__
. Portanto, você não pode fazer importações relativas diretamente de uma sessão interativa . As importações relativas são apenas para uso nos arquivos do módulo.
Duas soluções:
Se você realmente deseja executar moduleX
diretamente, mas ainda assim ele é considerado parte de um pacote, é possível python -m package.subpackage1.moduleX
. O -m
comando diz ao Python para carregá-lo como um módulo, não como o script de nível superior.
Ou talvez você realmente não queira executar moduleX
, apenas deseja executar outro script, digamos myfile.py
, que use funções internas moduleX
. Se for esse o caso, coloque myfile.py
em outro lugar - não dentro do package
diretório - e execute-o. Se dentro de myfile.py
você fizer coisas como from package.moduleA import spam
, vai funcionar bem.
Notas
Para qualquer uma dessas soluções, o diretório do pacote ( package
no seu exemplo) deve estar acessível no caminho de pesquisa do módulo Python ( sys.path
). Caso contrário, você não poderá usar nada no pacote de maneira confiável.
Desde o Python 2.6, o "nome" do módulo para fins de resolução de pacotes é determinado não apenas por seus __name__
atributos, mas também pelo __package__
atributo. É por isso que evito usar o símbolo explícito __name__
para me referir ao "nome" do módulo. Desde o Python 2.6, o "nome" de um módulo é eficaz __package__ + '.' + __name__
, ou apenas __name__
se __package__
for None
.)