O PEP 08 declara:
As importações são sempre colocadas na parte superior do arquivo, logo após qualquer comentário e documentação do módulo, e antes das globais e constantes do módulo.
No entanto, se a classe / método / função que estou importando for usada apenas em casos raros, certamente será mais eficiente fazer a importação quando for necessário?
Não é isso:
class SomeClass(object):
def not_often_called(self)
from datetime import datetime
self.datetime = datetime.now()
mais eficiente que isso?
from datetime import datetime
class SomeClass(object):
def not_often_called(self)
self.datetime = datetime.now()
fonte
Colocar a instrução de importação dentro de uma função pode impedir dependências circulares. Por exemplo, se você tiver 2 módulos, X.py e Y.py, e ambos precisarem importar um ao outro, isso causará uma dependência circular quando você importar um dos módulos, causando um loop infinito. Se você mover a instrução de importação em um dos módulos, ela não tentará importar o outro módulo até que a função seja chamada e esse módulo já seja importado, portanto, não haverá loop infinito. Leia aqui para mais informações - effbot.org/zone/import-confusion.htm
fonte
Adotei a prática de colocar todas as importações nas funções que as utilizam, em vez de na parte superior do módulo.
O benefício que recebo é a capacidade de refatorar com mais confiabilidade. Quando movo uma função de um módulo para outro, sei que a função continuará funcionando com todo o seu legado de teste intacto. Se eu tenho minhas importações na parte superior do módulo, quando movo uma função, acho que acabo gastando muito tempo obtendo as importações do novo módulo completas e mínimas. Um IDE de refatoração pode tornar isso irrelevante.
Há uma penalidade de velocidade como mencionado em outro lugar. Eu medi isso na minha inscrição e achei insignificante para meus propósitos.
Também é bom poder ver todas as dependências do módulo antecipadamente, sem recorrer à pesquisa (por exemplo, grep). No entanto, o motivo pelo qual me preocupo com as dependências do módulo é geralmente porque estou instalando, refatorando ou movendo um sistema inteiro que compreende vários arquivos, não apenas um único módulo. Nesse caso, vou realizar uma pesquisa global de qualquer maneira para garantir que tenho as dependências no nível do sistema. Portanto, não encontrei importações globais para ajudar na minha compreensão de um sistema na prática.
Eu costumo colocar a importação de
sys
dentro daif __name__=='__main__'
verificação e depois passar argumentos (comosys.argv[1:]
) para umamain()
função. Isso me permite usarmain
em um contexto emsys
que não foi importado.fonte
def main(): print(sys.argv); if True: import sys; main();
Você precisaria agruparif __name__=='__main__'
uma função para criar um novo espaço para nome.Na maioria das vezes, isso seria útil para clareza e sensibilidade, mas nem sempre é o caso. Abaixo estão alguns exemplos de circunstâncias em que as importações de módulos podem residir em outros lugares.
Primeiramente, você poderia ter um módulo com um teste de unidade do formulário:
Em segundo lugar, você pode ter um requisito para importar condicionalmente algum módulo diferente no tempo de execução.
Provavelmente, há outras situações em que você pode colocar importações em outras partes do código.
fonte
A primeira variante é realmente mais eficiente que a segunda quando a função é chamada zero ou uma vez. Com a segunda e subsequentes invocações, no entanto, a abordagem "importar todas as chamadas" é realmente menos eficiente. Consulte este link para uma técnica de carregamento lento que combina o melhor de ambas as abordagens, realizando uma "importação lenta".
Mas há outras razões além da eficiência para você preferir uma à outra. Uma abordagem é tornar muito mais claro para quem lê o código as dependências que este módulo possui. Eles também têm características de falha muito diferentes - a primeira falhará no tempo de carregamento se não houver um módulo "datetime", enquanto a segunda não falhará até que o método seja chamado.
Nota adicionada: No IronPython, as importações podem ser um pouco mais caras que no CPython porque o código está basicamente sendo compilado à medida que está sendo importado.
fonte
Curt faz um bom argumento: a segunda versão é mais clara e falhará no tempo de carregamento, mais tarde e inesperadamente.
Normalmente, não me preocupo com a eficiência do carregamento de módulos, pois é (a) muito rápido e (b) ocorre principalmente na inicialização.
Se você precisar carregar módulos pesados em momentos inesperados, provavelmente faz mais sentido carregá-los dinamicamente com a
__import__
função, e certifique - se de capturarImportError
exceções e manipulá-los de maneira razoável.fonte
Eu não me preocuparia com a eficiência de carregar o módulo muito cedo. A memória ocupada pelo módulo não será muito grande (assumindo que seja modular o suficiente) e o custo de inicialização será insignificante.
Na maioria dos casos, você deseja carregar os módulos na parte superior do arquivo de origem. Para alguém lendo seu código, fica muito mais fácil dizer qual função ou objeto veio de qual módulo.
Um bom motivo para importar um módulo para outro local do código é se ele é usado em uma instrução de depuração.
Por exemplo:
Eu poderia depurar isso com:
Obviamente, o outro motivo para importar módulos em outras partes do código é se você precisar importá-los dinamicamente. Isso ocorre porque você praticamente não tem escolha.
Eu não me preocuparia com a eficiência de carregar o módulo muito cedo. A memória ocupada pelo módulo não será muito grande (assumindo que seja modular o suficiente) e o custo de inicialização será insignificante.
fonte
É uma troca, que apenas o programador pode decidir fazer.
O caso 1 economiza um pouco de memória e tempo de inicialização, não importando o módulo datetime (e fazendo a inicialização necessária) até ser necessário. Observe que fazer a importação 'somente quando chamado' também significa fazê-lo 'sempre que chamado'; portanto, cada chamada após a primeira ainda está incorrendo em uma sobrecarga adicional ao fazer a importação.
O caso 2 economiza tempo de execução e latência importando data e hora antecipadamente, para que not_often_called () retorne mais rapidamente quando for chamado e também não incorrendo na sobrecarga de uma importação em todas as chamadas.
Além da eficiência, é mais fácil ver as dependências do módulo antecipadamente se as instruções de importação estiverem ... antecipadamente. Escondê-los no código pode dificultar a localização fácil de quais módulos dependem os módulos.
Pessoalmente, geralmente sigo o PEP, exceto em coisas como testes de unidade e que nem sempre quero carregar porque sei que eles não serão usados, exceto pelo código de teste.
fonte
sys.modules
consulta do módulo pode ser facilmente compensado pela economia em apenas ter que procurar um nome local em vez de um nome global.Aqui está um exemplo em que todas as importações estão no topo (esta é a única vez que eu preciso fazer isso). Quero poder encerrar um subprocesso no Un * x e no Windows.
(Em revisão: o que John Millikin disse.)
fonte
É como muitas outras otimizações - você sacrifica alguma legibilidade por velocidade. Como John mencionou, se você fez sua lição de casa de criação de perfil e achou uma alteração bastante útil o suficiente e precisa de velocidade extra, faça isso. Provavelmente seria bom anotar todas as outras importações:
fonte
A inicialização do módulo ocorre apenas uma vez - na primeira importação. Se o módulo em questão for da biblioteca padrão, você provavelmente o importará de outros módulos em seu programa. Para um módulo tão prevalente quanto a data e hora, também é provável que seja uma dependência para várias outras bibliotecas padrão. A declaração de importação custaria muito pouco, pois a inicialização do módulo já teria acontecido. Tudo o que está fazendo neste momento é vincular o objeto do módulo existente ao escopo local.
Associe essas informações ao argumento de legibilidade e eu diria que é melhor ter a declaração de importação no escopo do módulo.
fonte
Apenas para completar a resposta de Moe e a pergunta original:
Quando temos que lidar com dependências circulares, podemos fazer alguns "truques". Supondo que estamos trabalhando com módulos
a.py
eb.py
que contêmx()
eby()
, respectivamente. Então:from imports
na parte inferior do módulo.from imports
interna da função ou método que realmente exige a importação (isso nem sempre é possível, pois você pode usá-lo em vários locais).from imports
para ser uma importação que se parece com:import a
Então, para concluir. Se você não está lidando com dependências circulares e está fazendo algum tipo de truque para evitá-las, é melhor colocar todas as suas importações no topo por causa dos motivos já explicados em outras respostas a esta pergunta. E, por favor, ao fazer esses "truques" incluir um comentário, é sempre bem-vindo! :)
fonte
Além das excelentes respostas já dadas, vale ressaltar que a colocação das importações não é apenas uma questão de estilo. Às vezes, um módulo possui dependências implícitas que precisam ser importadas ou inicializadas primeiro, e uma importação de nível superior pode levar a violações da ordem de execução necessária.
Esse problema geralmente ocorre na API Python do Apache Spark, onde você precisa inicializar o SparkContext antes de importar qualquer pacote ou módulo pyspark. É melhor colocar as importações do pyspark em um escopo em que o SparkContext esteja garantido disponível.
fonte
Fiquei surpreso ao não ver os números de custo reais das verificações de carga repetidas já publicados, embora haja muitas boas explicações sobre o que esperar.
Se você importa na parte superior, recebe o acerto de carga, não importa o quê. Isso é bem pequeno, mas geralmente em milissegundos, não em nanossegundos.
Se você importar dentro de uma (s) função (s), será possível carregar apenas se e quando uma dessas funções for chamada pela primeira vez. Como muitos salientaram, se isso não acontecer, você economiza o tempo de carregamento. Mas se a função (s) se chamado de um monte, você toma um repetida embora hit muito menor (para verificar que ele tenha sido carregado, não para realmente re-loading). Por outro lado, como @aaronasterling apontou, você também economiza um pouco porque a importação em uma função permite que a função use pesquisas de variáveis locais um pouco mais rápidas para identificar o nome posteriormente ( http://stackoverflow.com/questions/477096/python- estilo de codificação de importação / 4789963 # 4789963 ).
Aqui estão os resultados de um teste simples que importa algumas coisas de dentro de uma função. Os tempos relatados (no Python 2.7.14 em um Intel Core i7 de 2,3 GHz) são mostrados abaixo (a segunda chamada, recebendo mais do que as chamadas posteriores, parece consistente, embora eu não saiba o porquê).
O código:
fonte
Não pretendo dar uma resposta completa, porque outros já o fizeram muito bem. Eu só quero mencionar um caso de uso quando achar especialmente útil importar módulos dentro de funções. Meu aplicativo usa pacotes e módulos python armazenados em determinado local como plugins. Durante a inicialização do aplicativo, o aplicativo percorre todos os módulos no local e os importa, depois olha dentro dos módulos e se encontra alguns pontos de montagem para os plug-ins (no meu caso, é uma subclasse de uma determinada classe base com uma classe única). ID) registra-os. O número de plugins é grande (agora dezenas, mas talvez centenas no futuro) e cada um deles é usado muito raramente. A importação de bibliotecas de terceiros na parte superior dos meus módulos de plug-in foi um pouco penosa durante a inicialização do aplicativo. Especialmente, algumas bibliotecas de terceiros são pesadas para importar (por exemplo, a importação de plotly tenta se conectar à Internet e baixar algo que estava adicionando cerca de um segundo à inicialização). Ao otimizar as importações (chamando-as apenas nas funções em que são usadas) nos plugins, consegui reduzir a inicialização de 10 segundos para cerca de 2 segundos. Essa é uma grande diferença para meus usuários.
Portanto, minha resposta é não, nem sempre coloque as importações na parte superior dos seus módulos.
fonte
É interessante que nenhuma resposta mencionou o processamento paralelo até agora, onde pode ser NECESSÁRIO que as importações estejam na função, quando o código de função serializado é o que está sendo enviado para outros núcleos, por exemplo, como no caso do ipyparallel.
fonte
Pode haver um ganho de desempenho importando variáveis / escopo local dentro de uma função. Isso depende do uso da coisa importada dentro da função. Se você estiver repetindo várias vezes e acessando um objeto global do módulo, importá-lo como local pode ajudar.
test.py
runlocal.py
run.py
Uma vez no Linux mostra um pequeno ganho
real é relógio de parede. usuário é tempo no programa. sys é hora de chamadas do sistema.
https://docs.python.org/3.5/reference/executionmodel.html#resolution-of-names
fonte
Legibilidade
Além do desempenho da inicialização, há um argumento de legibilidade a ser feito para localizar
import
instruções. Por exemplo, considere os números de linha python 1283 a 1296 no meu primeiro projeto python atual:Se a
import
declaração estivesse no topo do arquivo, eu teria que percorrer um longo caminho, ou pressionar Home, para descobrir o queET
era. Então eu teria que voltar para a linha 1283 para continuar lendo o código.De fato, mesmo que a
import
instrução estivesse no topo da função (ou classe), como muitos a colocariam, seria necessária uma paginação para cima e para trás.A exibição do número da versão do Gnome raramente será feita, portanto o
import
início do arquivo apresenta um atraso de inicialização desnecessário.fonte
Gostaria de mencionar um caso meu, muito parecido com o mencionado por John Millikin e @VK:
Importações opcionais
Faço análise de dados com o Jupyter Notebook e uso o mesmo notebook IPython como modelo para todas as análises. Em algumas ocasiões, preciso importar o Tensorflow para executar algumas execuções rápidas do modelo, mas às vezes trabalho em locais onde o tensorflow não está configurado / é lento para importar. Nesses casos, encapsulo minhas operações dependentes do fluxo de tensor em uma função auxiliar, importo o fluxo de tensor dentro dessa função e vinculo-o a um botão.
Dessa maneira, eu poderia fazer "reiniciar e executar tudo" sem ter que esperar pela importação ou ter que continuar o restante das células quando ela falhar.
fonte
Esta é uma discussão fascinante. Como muitos outros, eu nunca havia considerado esse tópico. Eu fui obrigado a ter as importações nas funções por querer usar o Django ORM em uma das minhas bibliotecas. Eu estava tendo que ligar
django.setup()
antes de importar minhas classes de modelo e, como estava no topo do arquivo, ele estava sendo arrastado para um código de biblioteca completamente não-Django, devido à construção do injetor de IoC.Eu meio que entrei um pouco e acabei colocando o
django.setup()
construtor singleton e a importação relevante na parte superior de cada método de classe. Agora isso funcionou bem, mas me deixou desconfortável porque as importações não estavam no topo e também comecei a me preocupar com o tempo extra atingido. Então eu vim aqui e li com grande interesse que todos entendem isso.Eu tenho um longo histórico de C ++ e agora uso Python / Cython. Minha opinião é que, por que não colocar as importações na função, a menos que isso cause um gargalo com perfil. É como declarar espaço para variáveis antes que você precise delas. O problema é que tenho milhares de linhas de código com todas as importações no topo! Então, acho que vou fazê-lo a partir de agora e alterar o arquivo ímpar aqui e ali quando estiver passando e tiver tempo.
fonte