Importando módulos Python no momento do uso

8

Muitas vezes, nas minhas bibliotecas pessoais do Python, faço algo assim:

class MyClass:

    # ...

    def plot(self):
        import someGraphicsLibrary as graphicslib
        graphicslib.plot(self.data)

O motivo é que a inicialização someGraphicsLibraryleva algum tempo, até alguns segundos para uma das bibliotecas que eu uso. Nem sempre preciso plotar meus resultados quando uso essa classe; portanto, faz sentido não importá-lo até o momento em que ele é realmente usado, se for o caso.

Isso parece funcionar bem, mas acho que não vi no código de ninguém. Portanto, minha pergunta é simplesmente se isso é considerado uma boa prática. Existem armadilhas ocultas que se espera ao fazer as coisas dessa maneira?

Nathaniel
fonte
1
Esta é simplesmente uma forma de carregamento lento , que não é muito especial.
Doc Brown
1
Além de ser um pouco feio, não há nenhuma razão real para você não conseguir fazer isso. E se a importação da biblioteca demorar tanto, existe até uma causa legítima para isso. Eu apenas faria questão de fazer isso raramente. A maioria das importações não deve ser tão lenta.
194 Neil
@DocBrown Não estou dizendo que é especial, apenas perguntando se é considerada uma boa / má prática especificamente em Python.
Nathaniel
@ Nathaniel: parece haver um certo supersticioso na existência de "melhores práticas" absolutas entre muitos desenvolvedores - o que é um absurdo do IMHO, qualquer "prática" tem prós e contras, e o que é bom ou ruim só pode ser avaliado no específico contexto. Seu exemplo acima parece razoável para mim, é simples e claro, e a única desvantagem real é que fica mais difícil ver todas as dependências de um módulo rapidamente (que é o ponto 3 da resposta de Kevin). Portanto, se você acha que a melhoria no desempenho vale a pena, então essa prática é boa; se não, essa prática é ruim.
Doc Brown

Respostas:

9

Isso geralmente não é uma boa prática, por vários motivos:

  1. Na maioria das vezes, o método será rápido, mas a primeira vez que você o chamar, será lento. Isso é muito menos previsível do que uma importação no momento da inicialização.
  2. Se a importação falhar por vários motivos, você não saberá até chamar o método em tempo de execução.
  3. É mais difícil ver de quais módulos seu módulo depende, porque eles não estão listados na parte superior do arquivo.
  4. Se um módulo leva literalmente "alguns segundos" para importar, pode estar fazendo muito em sua lógica do tempo de importação. A lógica do tempo de importação geralmente deve fazer "apenas o suficiente" para tornar o módulo utilizável e não deve criar objetos globais pesados. Ocasionalmente, esses objetos são necessários, mas devem ser cuidadosamente examinados.

No entanto, às vezes isso é uma boa ideia, por exemplo:

  1. Ao implementar um array , você pode precisar usar numpyseu __array__()método. Mas você pode não querer depender numpydas outras funcionalidades do seu módulo; portanto, é melhor importar apenas o numpyinterior __array__()para evitar a dependência extra quando não for necessário. Isso não sofre dos problemas 1 e 2 porque numpyjá foi importado uma vez antes (é o que está chamando __array__()em primeiro lugar!), E não sofre do problema 3 porque numpynão é uma dependência "real" do seu módulo.
  2. Antes de PEP 553 , um ponto de interrupção, tradicionalmente, era assim: import pdb; pdb.set_trace(). Você não deseja colocar import pdbna parte superior do módulo porque o ponto de interrupção é uma linha temporária de código que será excluída, e mover a importação para longe tornaria isso desnecessariamente difícil. Isso ficou obsoleto quando o builtin breakpoint()foi adicionado, então agora você não precisa de uma importação embutida.
Kevin
fonte
4
Você esqueceu de mencionar que o exemplo postado pelo OP se parece com o que se encaixa no caso "Boa idéia nº 1" em sua resposta. Parece uma classe ou módulo que possui uma funcionalidade principal que é independente da plotagem e pode ser usada sem a biblioteca de gráficos.
Doc Brown
@ DocBrown: MyClassnão é um substantivo significativo, então eu acho que você está tirando conclusões precipitadas.
Kevin
Bem, reservei um tempo para ler o post na íntegra. Talvez eu tenha adivinhado, mas vamos ver o que o OP pensa sobre isso (e não me interpretem mal, sua resposta já recebeu um voto positivo de mim).
Doc Brown
O primeiro comentário de Kevin Doc Brown é uma interpretação correta do meu post. (+1, esta é uma resposta útil.) #
1313 Nathaniel Nathaniel