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.