Por que "import *" é ruim?


153

É recomendável não usar import *no Python.

Alguém pode compartilhar o motivo disso, para que eu possa evitar isso da próxima vez?



2
isso depende se você estiver escrevendo ou escrevendo um código que precisa reutilizar. às vezes vale a pena ignorar os padrões de código. "import *" também pode ser bom se você tiver uma convenção de nomenclatura que deixe claro de onde vieram as coisas. por exemplo "dos gatos import *; TabbyCat; MaineCoonCat; CalicoCat;"
— gatoatigrado 21/07

3
import *não funciona para mim em primeiro lugar no Python 2 ou 3.
— joshreesjones

1
Isso responde sua pergunta? O que exatamente "import *" importa?
— AMC

Respostas:


223
  • Porque coloca um monte de coisas no seu espaço para nome (pode ocultar outro objeto da importação anterior e você não o saberá).

  • Porque você não sabe exatamente o que é importado e não consegue encontrar facilmente de qual módulo uma determinada coisa foi importada (legibilidade).

  • Porque você não pode usar ferramentas legais, como pyflakesdetectar estaticamente erros no seu código.


2
Sim, eu realmente odeio o meu trabalho quando alguém usa * import, porque então não posso simplesmente executar pyflakes e ser feliz, mas tenho que reparar essas importações. É bom, porém, que, com essa pyflakes me ajuda a :-)
— gruszczy

7
Como um exemplo concreto, muitos usuários do NumPy foram mordidos pela numpy.anysombra anyquando o fazem from numpy import *ou uma ferramenta "útil" faz isso por eles.
— User2357112 suporta Monica

1
Devo evitar usar a opção --pylab para IPython pelos mesmos motivos?
— timgeb

6
Para destacar um risco que eu nunca tinha pensado antes de ler isso ("pode ​​ocultar outro objeto da importação anterior"): import *torna a ordem das importinstruções significativa ... mesmo para os módulos de biblioteca padrão que normalmente não se importam com a ordem de importação . Algo tão inocente quanto colocar em ordem alfabética suas importdeclarações pode quebrar seu script quando uma ex-vítima da guerra de importação se torna o único sobrevivente. (Mesmo que o seu script funciona agora e nunca muda, pode falhar de repente em algum momento mais tarde, se as introduz módulo importado um novo nome que substitui um você estava contando com.)
— Kevin J. perseguição

49

De acordo com o Zen de Python :

Explícito é melhor que implícito.

... não posso discutir com isso, com certeza?


29
Na verdade, você pode argumentar com isso. Também é totalmente inconsistente, já que você não declara variáveis ​​explicitamente no Python, elas apenas surgem quando você as atribui.
— Konrad Rudolph

7
@gruszczy: declarar variáveis ​​é redundante para quê ? Atribuindo? Não, são dois conceitos separados e declarar algo transmite uma informação muito distinta e importante. De qualquer forma, a explicitação está sempre um pouco ligada à redundância, são duas faces da mesma moeda.
— Konrad Rudolph

3
@ Kriss certo, mas esse não era o meu ponto. Meu argumento foi que a falha em declarar explicitamente uma variável leva a erros. Você diz que "a atribuição sem [declaração] é impossível". Mas isso está errado, meu argumento é que, infelizmente, o Python torna exatamente isso possível.
— Konrad Rudolph

3
@kriss Outra informação fornecida ao compilador pela declaração é o fato de que você realmente pretende declarar uma nova variável. Essa é uma informação crucial para o sistema de tipos. Você diz que os IDEs modernos resolvem o problema de digitação incorreta, mas isso é simplesmente errado e, de fato, esse é um problema substancial em linguagens não compiladas estaticamente, e é por isso que o Perl adicionou use strict(JavaScript var). Como um aparte, é claro que o Python não é digitado (na verdade, é fortemente tipado). De qualquer forma, mesmo se você estivesse certo, isso ainda contradiz o Zen de Python, citado nesta resposta.
— Konrad Rudolph

3
@kriss Você está errado: reutilizar o mesmo nome de variável não é um problema - reutilizar a mesma variável é (ou seja, o mesmo nome no mesmo escopo). Declarações explícitas impediriam exatamente esse erro (e outras, baseadas em erros de digitação simples, o que, como eu disse, é realmente um problema extremamente comum e demorado, mesmo que você esteja certo de que o problema é maior no tipo Perl línguas). E a contradição a que aludo é o requisito de explicitação do Zen, que é jogado corporalmente pela janela aqui.
— Konrad Rudolph

40

Você não passa **locals() para funções, não é?

Como o Python não possui uma instrução "include" e o selfparâmetro é explícito, e regras de escopo são bastante simples, geralmente é muito fácil apontar um dedo para uma variável e dizer de onde vem esse objeto - sem ler outros módulos e sem nenhum tipo do IDE (que de qualquer maneira é limitado na introspecção, pelo fato de a linguagem ser muito dinâmica).

o import * quebra tudo isso.

Além disso, tem uma possibilidade concreta de ocultar bugs.

import os, sys, foo, sqlalchemy, mystuff
from bar import *

Agora, se o módulo de barra tiver alguma das "osmystuff atributos ", " ", etc ..., eles substituirão os importados explicitamente e possivelmente apontarão para coisas muito diferentes. A definição __all__de barra é geralmente sábia - isso indica o que implicitamente será importado - mas ainda é difícil rastrear a origem dos objetos, sem ler e analisar o módulo de barras e seguir suas importações. Uma rede deimport * é a primeira coisa que conserto quando me aproprio de um projeto.

Não me entenda mal: se import *faltava, eu choraria por tê-lo. Mas tem que ser usado com cuidado. Um bom caso de uso é fornecer uma interface de fachada sobre outro módulo. Da mesma forma, o uso de instruções de importação condicionais, ou importações dentro de namespaces de função / classe, requer um pouco de disciplina.

Eu acho que em projetos de médio a grande porte ou pequenos com vários colaboradores, é necessária uma higiene mínima em termos de análise estática - executando pelo menos flocos de neve ou, melhor ainda, um pylint configurado corretamente - para capturar vários tipos de erros antes eles acontecem.

É claro que, como se trata de python - sinta-se à vontade para violar regras e explorar -, mas tenha cuidado com projetos que podem crescer dez vezes, se o código-fonte estiver com falta de disciplina, será um problema.


6
Python 2.x faz ter uma declaração "incluir". É chamado execfile(). Felizmente, raramente é usado e usado no 3.x.
— Sven Marnach

Que tal **vars()incluir globais se a função chamada estiver em outro arquivo? : P
— Solomon Ucko,

16

Não há problema em fazer from ... import *uma sessão interativa.


Que tal dentro de uma doctestcorda? O import *interpretado dentro de uma "caixa de areia" neste caso? Obrigado.
— PatrickT

16

Isso é porque você está poluindo o espaço para nome. Você importará todas as funções e classes em seu próprio espaço para nome, o que pode colidir com as funções que você mesmo define.

Além disso, acho que usar um nome qualificado é mais claro para a tarefa de manutenção; você vê na própria linha de código de onde vem uma função, para que você possa conferir os documentos com muito mais facilidade.

No módulo foo:

def myFunc():
    print 1

No seu código:

from foo import *

def doThis():
    myFunc() # Which myFunc is called?

def myFunc():
    print 2


9

Digamos que você tenha o seguinte código em um módulo chamado foo:

import ElementTree as etree

e então em seu próprio módulo você tem:

from lxml import etree
from foo import *

Agora você tem um módulo difícil de depurar, que parece ter o lreex etree, mas realmente possui o ElementTree.


7

Todas essas são boas respostas. Vou acrescentar que, ao ensinar novas pessoas a codificar em Python, lidar comimport * é muito difícil. Mesmo se você ou eles não escreveram o código, ainda é um obstáculo.

Eu ensino crianças (cerca de 8 anos) a programar em Python para manipular o Minecraft. Eu gosto de oferecer a eles um ambiente de codificação útil para trabalhar com ( Atom Editor ) e ensinar desenvolvimento orientado a REPL (via bpython ). No Atom, acho que as dicas / conclusão funcionam tão eficientemente quanto o bpython. Felizmente, ao contrário de outras ferramentas de análise estatística, o Atom não se deixa enganar import *.

No entanto, vamos dar este exemplo ... Neste wrapper, eles from local_module import *agrupam vários módulos, incluindo esta lista de blocos . Vamos ignorar o risco de colisões de namespace. Ao fazer isso, from mcpi.block import *eles fazem dessa lista inteira de tipos obscuros de blocos algo que você deve procurar para saber o que está disponível. Se eles tivessem usado from mcpi import block, você poderia digitar walls = block.e uma lista de preenchimento automático apareceria. Imagem de Atom.io


6

Entendeu os pontos válidos que as pessoas colocam aqui. No entanto, tenho um argumento de que, às vezes, "importação em estrela" nem sempre pode ser uma prática ruim:

  • Quando eu quero estruturar meu código de forma que todas as constantes vão para um módulo chamado const.py :
    • Se sim import const, então, para cada constante, tenho que referir como const.SOMETHING, o que provavelmente não é a maneira mais conveniente.
    • Se sim from const import SOMETHING_A, SOMETHING_B ..., obviamente é muito detalhado e derrota o objetivo da estruturação.
    • Portanto, nesse caso, sinto que fazer uma from const import *pode ser uma escolha melhor.

4

É uma prática muito ruim por duas razões:

  1. Legibilidade do código
  2. Risco de substituir as variáveis ​​/ funções etc

Para o ponto 1 : vamos ver um exemplo disso:

from module1 import *
from module2 import *
from module3 import *

a = b + c - d

Aqui, ao ver o código ninguém vai ter idéia a respeito de qual módulo b, ced na verdade pertence.

Por outro lado, se você fizer o seguinte:

#                   v  v  will know that these are from module1
from module1 import b, c   # way 1
import module2             # way 2

a = b + c - module2.d
#            ^ will know it is from module2

É muito mais limpo para você, e também a nova pessoa que se juntará à sua equipe terá uma ideia melhor.

Para o ponto 2 : Digamos ambos module1e module2tenha variável como b. Quando eu faço:

from module1 import *
from module2 import *

print b  # will print the value from module2

Aqui o valor de module1é perdido. Será difícil depurar por que o código não está funcionando, mesmo que bseja declarado module1e eu escrevi o código esperando que meu código fosse usadomodule1.b

Se você possui as mesmas variáveis ​​em módulos diferentes e não deseja importar o módulo inteiro, pode até fazer:

from module1 import b as mod1b
from module2 import b as mod2b

2

Como teste, criei um módulo test.py com 2 funções A e B, que imprimem respectivamente "A 1" e "B 1". Após importar o test.py com:

import test

. . . Eu posso executar as 2 funções como test.A () e test.B () e "test" aparece como um módulo no espaço para nome; portanto, se eu editar test.py, posso recarregá-lo com:

import importlib
importlib.reload(test)

Mas se eu fizer o seguinte:

from test import *

não há referência a "teste" no espaço para nome; portanto, não há como recarregá-lo após uma edição (pelo que sei), o que é um problema em uma sessão interativa. Considerando que um dos seguintes:

import test
import test as tt

adicionará "test" ou "tt" (respectivamente) como nomes de módulo no espaço para nome, o que permitirá o recarregamento.

Se eu fizer:

from test import *

os nomes "A" e "B" aparecem no espaço para nome como funções . Se eu editar test.py e repetir o comando acima, as versões modificadas das funções não serão recarregadas.

E o comando a seguir gera uma mensagem de erro.

importlib.reload(test)    # Error - name 'test' is not defined

Se alguém souber recarregar um módulo carregado com "from module import *", poste. Caso contrário, esse seria outro motivo para evitar o formulário:

from module import *

2

Conforme sugerido nos documentos, você nunca deve (quase) usar import *no código de produção.

Embora a importação *de um módulo seja ruim, a importação * de um pacote é ainda pior. Por padrão, from package import *importa quaisquer nomes que sejam definidos pelos pacotes __init__.py, incluindo quaisquer submódulos do pacote carregados por versões anteriores.import instruções .

No entanto, se o __init__.pycódigo de um pacote definir uma lista denominada __all__, será considerada a lista de nomes de sub-módulos que devem ser importados quando from package import *encontrados.

Considere este exemplo (supondo que não haja um __all__definido em sound/effects/__init__.py):

# anywhere in the code before import *
import sound.effects.echo
import sound.effects.surround

# in your module
from sound.effects import *

A última instrução importará os módulos echoe surroundno espaço para nome atual (possivelmente substituindo as definições anteriores) porque elas são definidas no sound.effectspacote quando a importinstrução é executada.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.