Python: Qual é o sentido de usar "import"?

8

Não sou muito claro sobre esse aspecto. Digamos que você tenha um monte de arquivos .py que são seus próprios módulos separados.

Por que cada arquivo .py precisa importar os outros quando eles usam essa classe? Ou eles? Porque eu tinha quase certeza de que outras linguagens (Java, por exemplo), não exigiam importação quando se referiam a classes / arquivos no mesmo diretório. Eu posso estar errado.

Kaitlyn Mcmordie
fonte

Respostas:

8

Simplificando, foi assim que foi projetado. Você mencionou o Java como um exemplo contrário - os designers de linguagem Java queriam tornar o carregamento de classe um pouco implícito, para que eles verificassem o mesmo diretório antes de lançar ClassNotFound. Fora isso, você precisa se qualificar, assim como no Python.

Como Tom Anderson disse, C faz o mesmo que Python, e é uma linguagem compilada. Talvez a natureza interpretada da linguagem tenha algo a ver com a decisão final (por desempenho, testemunha etc.), mas no final depende do desenvolvedor.

Michael K
fonte
Não tenho certeza de que "é assim que foi projetado" seja realmente a resposta para essa pergunta.
Winston Ewert
2
-1: Não conheço bem o Python, mas entendo que você precisa importar um pacote para usar qualquer coisa nele. Em Java, tecnicamente, você nunca precisa usar instruções de importação; você pode simplesmente escrever os nomes completos e qualificados das classes etc. em outros pacotes.
compman
1
Qualificação é resolver o caminho para um objeto (classe, função, qualquer que seja). Se isso é feito por importadores ou qualificadores de sintaxe, é irrelevante.
Michael K
3

Como o python é interpretado, tudo o que você importa está disponível no prompt. Java (e C ++) têm uma etapa de compilação e link que pode pesquisar e incluir apenas funções usadas

Se tudo fosse importado automaticamente, haveria milhares de funções e variáveis ​​e seria impossível digitar qualquer coisa sem colidir com uma.

edit: Ok, é um pouco mais do que apenas compilado versus interpretado. O Python pretende ser uma linguagem "baterias incluídas" - existem bibliotecas disponíveis para fazer quase tudo. Como você só usará uma pequena fração dessas pessoas, é preciso organizá-las para incluir apenas as que você precisa.

A importação da sintaxe é inteligente porque você pode importar a biblioteca inteira e manter nomes totalmente qualificados do tipo Java ou importar funções específicas (ou todas as funções) no espaço de nomes local

>>>import math
>>> math.sin(0)  #no confusion with any other 'sin'

>>> from math import sin  # or import *
>>> sin(0) # makes equations with sin shorter and simpler

A segunda razão é especialmente importante em uma linguagem dinâmica como python. Como você não precisa definir variáveis ​​antes de usá-las, seria difícil para o ambiente descobrir se siné a função matemática ou uma variável sua em um intérprete.

Martin Beckett
fonte
Eu não entendo ... Você poderia explicar isso para um newb? :(
Chuck Testa
@ChuckTesta Para entender completamente a diferença discutida nesta resposta, você precisa entender a diferença entre idiomas compilados e interpretados - esta publicação do blog resume tudo em termos bastante simples: blog.julipedia.org/2004/07/…
Bob
8
A diferença não tem absolutamente nada a ver com interpretado vs compilado. Você poderia escrever um compilador Python e teria que funcionar exatamente da mesma maneira que o interpretador Python. A diferença é simplesmente que os designers de Java (digamos) decidiram adicionar o carregamento implícito de classes de outros arquivos, e os designers de Python não. Observe que C é compilado, mas possui essencialmente as mesmas regras que o Python - você não pode usar uma função de outro arquivo, a menos que #inclua um cabeçalho para ele e vincule a biblioteca correta.
Tom Anderson
2
O ponto é válido: o carregamento implícito de classe teria um grande custo de tempo de execução em uma linguagem interpretada
Simon Bergot
1
@ Simon, por que teria um grande custo de tempo de execução?
Winston Ewert
1

Imagine que você tinha esse código em python:

foo = MyObject()
fo.bar()

Obviamente, temos um erro de digitação e fodeveria ter sido foo. No momento, o python diz:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'fo' is not defined

Mas com o carregamento implícito de classe, pode-se dizer:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named fo

o que seria confuso. Pior ainda, se você digitasse incorretamente um nome de variável que por acaso era o nome de um módulo, você receberia um erro ainda mais confuso ao tentar tratar esse módulo como se fosse sua variável. Python não pode dizer se algo é um nome de classe, objeto ou qualquer outra coisa.

Java, por outro lado, acredito que pode distinguir da sintaxe se um determinado identificador se refere a uma classe ou outra coisa. Portanto, não há problema em produzir uma mensagem de erro apropriada.

No geral, ele se encaixa na filosofia Python de ser explícito e não implícito. Eles acham melhor importar explicitamente um módulo, em vez de importá-lo automaticamente. O problema da mensagem de erro é um fator que influencia a decisão.

Alguns sugeriram que haveria um grande custo de tempo de execução para importações implícitas. Acho que não. O que acontece é algo como isto:

  1. Código de operação LOAD_GLOBAL chamado com o nome "foo"
  2. dicionário global verificado para "foo"
  3. dicionário embutido verificado para "foo"
  4. Se for encontrado, armazene em globais e continue
  5. Se foo não encontrado, aumente NameError

Para suportar o carregamento implícito do módulo, poderíamos fazer:

  1. Código de operação LOAD_GLOBAL chamado com o nome "foo"
  2. dicionário global verificado para "foo"
  3. dicionário embutido verificado para "foo"
  4. Se o acima falhar, tente import foo
  5. Se for encontrado, armazene em globais e continue
  6. Se foo não encontrado, aumente NameError

Na primeira vez em que o módulo é usado, levaria um pouco mais de tempo, pois ele deve procurar outros dicionários primeiro. Mas essa é apenas a primeira vez e não deve ser significativa em termos de tempo de execução do programa.

Haveria um custo significativo, no caso de nomes de variáveis ​​com erros ortográficos. Quando ocorrem, o python perde tempo lendo o disco tentando encontrar o módulo. Mas se isso acontecer, seu programa está prestes a morrer com um retorno, e o desempenho não é uma grande preocupação.

Winston Ewert
fonte
1

Existem algumas diferenças importantes entre Python e Java; enquanto o Java tem uma regra "uma classe por arquivo", o Python não. Além disso, nem tudo no Python é uma classe.

Portanto, um módulo pode ter classes, funções e simplesmente variáveis ​​antigas - geralmente todas relacionadas de alguma forma (como funções aleatórias random, rotinas matemáticas math, constantes de string string, etc).

Se você quiser acessar qualquer uma das classes / funções / variáveis ​​de um módulo específico, primeiro importe-o.

Por que isso é uma coisa boa?

  • Mantém os espaços de nomes dos módulos limpos (sem confusão de nomes que você nunca usará)
  • Mais fácil rastrear o módulo apropriado quando algo der errado
  • Permite que você use nomes sem medo de um erro, porque o nome está em uso ou derruba o nome já em uso (você pode ter math.sine suas próprias sinfunções)
  • Ajuda a esclarecer a estrutura do programa.
Ethan Furman
fonte
1

Um dos conceitos mais importantes do Python é o de namespaces (faça isso import thisimediatamente, para descobrir quais são os outros). Eu sei que os espaços para nome também existem em outros idiomas, mas no Python você só tem acesso ao espaço para nome atual, que é o que é definido no módulo atual. Para obter acesso a outros identificadores, é necessário importá-los para o espaço para nome atual: importando o módulo que os contém (a import foosintaxe) ou os próprios nomes ( from foo import bar).

Daniel Roseman
fonte