2010-03-05 21 views
95

Se recomienda no usar import * en Python.¿Por qué es "import *" malo?

¿Alguien puede por favor compartir la razón de eso, para que pueda evitarlo la próxima vez?

+0

duplicado: http://stackoverflow.com/questions/2360724/in-python-what-exactly-does-import-import –

+0

que depende de si está escribiendo o escribiendo código que necesita volver a usar. a veces vale la pena ignorar los estándares del código. "importar *" también puede estar bien si tiene una convención de nomenclatura que aclara de dónde provienen las cosas. p.ej. "de la importación de gatos *; TabbyCat; MaineCoonCat; CalicoCat;" – gatoatigrado

+1

'import *' no funciona para mí en primer lugar en Python 2 o 3. – joshreesjones

Respuesta

148
  • Porque pone muchas cosas en su espacio de nombres (puede ensombrecer algún otro objeto de importación anterior y no lo sabrá).

  • Porque no sabe exactamente qué se importa y no puede encontrar lugar desde qué módulo se importó algo con facilidad (legibilidad).

  • Porque no puede usar herramientas geniales como pyflakes para detectar errores estáticos en su código.

+7

+1 porque era más rápido que yo y también agregó el argumento de pyflakes. Debería haber sido +2 pero no puedo dar eso :) – extraneon

+1

Sí, realmente odio en mi trabajo cuando alguien usa * import, porque entonces no puedo simplemente ejecutar pyflakes y ser feliz, sino que tengo que reparar esas importaciones. Sin embargo, es agradable que con ese pyflakes me ayude a :-) – gruszczy

+3

Como ejemplo concreto, muchos usuarios de NumPy han sido mordidos por 'numpy.any' sombreando' any' cuando lo hacen 'from numpy import *' o "helpful" "la herramienta lo hace por ellos". – user2357112

15

Eso es porque está contaminando el espacio de nombres. Importará todas las funciones y clases en su propio espacio de nombres, lo que puede entrar en conflicto con las funciones que defina usted mismo.

Además, creo que usar un nombre calificado es más claro para la tarea de mantenimiento; se ve en la línea de código de donde proviene una función, por lo que puede ver los documentos mucho más fácilmente.

En el módulo foo:

def myFunc(): 
    print 1 

En su código:

from foo import * 

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

def myFunc(): 
    print 2 
+3

+1 para mencionar la contaminación del espacio de nombres –

12

Está bien hacer from ... import * en una sesión interactiva.

37

De acuerdo con la Python Zen:

Explícito es mejor que implícito.

... no se puede discutir con eso, ¿no?

+0

De acuerdo. También estoy de acuerdo con las otras publicaciones sobre posibles colisiones de espacios de nombres. – smencer

+8

En realidad, * puedes * discutir eso. También es totalmente inconsistente, dado que no declaras variables explícitamente en Python, simplemente aparecen una vez que les asignas. –

+0

Porque declarar variables no es explícito, es redundante, así como declarar sus tipos. Es por eso que C++ va a presentar 'auto', de lo cual soy un gran admirador. Aunque eso también es redundante :-) – gruszczy

7

Digamos que tiene el siguiente código en un módulo llamado foo:

import ElementTree as etree 

y luego en su propio módulo tiene:

from lxml import etree 
from foo import * 

Ahora tiene un módulo de difícil depuración que parece tiene etree de lxml, pero realmente tiene ElementTree en su lugar.

26

No pasa **locals() a funciones, ¿o sí?

Como Python carece de una declaración de "incluir", y el parámetro self es explícita, y reglas de alcance son muy simples, por lo general es muy fácil señalar con el dedo a una variable y decir donde ese objeto proviene de - - sin leer otros módulos y sin ningún tipo de IDE (que están limitados en el modo de introspección de todos modos, por el hecho de que el lenguaje es muy dinámico).

El import * rompe todo eso.

Además, tiene una posibilidad concreta de ocultar errores.

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

Ahora, si el módulo bar tiene cualquiera de los "os", "mystuff", etc ... atributos, que prevalecerá sobre las importadas de manera explícita queridos, y posiblemente apuntar a cosas muy diferentes. Definir __all__ en la barra suele ser prudente; esto indica lo que se importará implícitamente, pero aún así es difícil rastrear de dónde vienen los objetos, sin leer ni analizar el módulo de la barra y después de importarlos. Una red de import * es lo primero que soluciono cuando tomo posesión de un proyecto.

No me malinterpreten: si faltara el import *, lloraría por tenerlo. Pero debe usarse con cuidado. Un buen caso de uso es proporcionar una interfaz de fachada sobre otro módulo. Del mismo modo, el uso de sentencias de importación condicionales o importaciones dentro de espacios de nombres de clase/función requiere un poco de disciplina.

Creo que en proyectos medianos a grandes, o pequeños con varios contribuyentes, se necesita un mínimo de higiene en términos de análisis estático - ejecutando al menos los copos o incluso mejor una capa configurada correctamente - para atrapar varios tipo de errores antes de que sucedan.

Por supuesto, dado que se trata de Python, siéntete libre de romper reglas y explorar, pero ten cuidado con los proyectos que podrían multiplicarse por diez, si el código fuente no tiene disciplina, será un problema.

+10

Me gusta tu actitud. – Joshua

+4

Python 2.x * does * tiene una instrucción "include". Se llama 'execfile()'. Afortunadamente, rara vez se usa y desapareció en 3.x. –

+0

¿Qué tal '' vars() 'para incluir globales si la función llamada está en otro archivo? :PAG –

5

Estas son todas buenas respuestas. Voy a agregar que cuando se enseña a las personas nuevas a codificar en Python, lidiar con import * es muy difícil. Incluso si usted o ellos no escribieron el código, sigue siendo un obstáculo.

Enseño a niños (alrededor de 8 años) a programar en Python para manipular Minecraft. Me gusta darles un entorno de codificación útil para trabajar con (Atom Editor) y enseñar el desarrollo impulsado por REPL (a través de bpython). En Atom encuentro que las sugerencias/finalización funcionan tan bien como bpython. Afortunadamente, a diferencia de otras herramientas de análisis estadístico, Atom no se deja engañar por import *.

Sin embargo, tomemos este ejemplo ... En this wrapper ellos from local_module import * un grupo de módulos incluyendo this list of blocks. Vamos a ignorar el riesgo de colisiones de espacios de nombres. Al hacer from mcpi.block import * hacen que toda esta lista de tipos de bloques oscuros sea algo que hay que consultar para saber qué hay disponible. Si en su lugar hubieran usado from mcpi import block, entonces podría escribir walls = block. y luego aparecería una lista de autocompletar. Atom.io screenshot

1

Es un muy malo la práctica por dos razones:

  1. la legibilidad del código
  2. riesgo de menoscabar las variables/funciones etc

Para el punto 1: Veamos una ejemplo de esto:

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

a = b + c - d 

Aquí, al ver el código nadie va a conseguir idea acerca de qué módulo b, c y d pertenece en realidad.

Por otro lado, si lo haces así:

#     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 

es mucho más limpio para usted, y también la nueva persona unirse a su equipo tendrá una mejor idea.

Para punto 2: Vamos a decir tanto module1 y module2 tienen variable como b. Cuando hago:

from module1 import * 
from module2 import * 

print b # will print the value from module2 

Aquí el valor de module1 está perdido. Será difícil para depurar por qué el código no funciona incluso si b se declara en module1 y he escrito el código esperando mi código para utilizar module1.b

Si tiene mismas variables en diferentes módulos, y no quieren importar todo el módulo, incluso puede hacerlo:

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

Entendemos los puntos válidos que las personas ponen aquí. Sin embargo, tengo un argumento que, a veces, "importar estrella" no siempre será una mala práctica:

  • Cuando quiero estructurar mi código de una manera tal que todas las constantes van a un módulo llamado const.py:
    • Si hago import const, a continuación, para cada constante, que tienen que referirse como const.SOMETHING, que no es probablemente la forma más conveniente.
    • Si hago from const import SOMETHING_A, SOMETHING_B ..., entonces obviamente es demasiado detallado y frustra el propósito de la estructuración.
    • Por lo tanto, creo que en este caso, hacer una from const import * puede ser una mejor opción.
2

Como prueba, he creado un test.py módulo con 2 funciones A y B, que imprime respectivamente "A 1" y "B 1". Después de importar test.py con:

import test 

. . . Puedo ejecutar las 2 funciones como test.A() y probar.B(), y "prueba" se muestra como un módulo en el espacio de nombres, por lo que si puedo editar test.py I pueden recargar con:

import importlib 
importlib.reload(test) 

Pero si hago lo siguiente:

from test import * 

no hay ninguna referencia a "prueba" en el espacio de nombres, por lo que no hay forma de volver a cargarlo después de una edición (hasta donde puedo decir), que es un problema en una sesión interactiva. Mientras que uno de los siguientes:

import test 
import test as tt 

añadirá "prueba" o "TT" (respectivamente) como nombres de los módulos en el espacio de nombres, lo que permitirá volver a la carga.

Si hago:

from test import * 

los nombres de "A" y "B" se muestran en el espacio de nombres como funciones. Si edito test.py y repito el comando anterior, las versiones modificadas de las funciones no se vuelven a cargar.

Y el siguiente comando provoca un mensaje de error.

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

Si alguien sabe cómo cargar un módulo cargado con "de importación de módulo *", por favor puesto. De lo contrario, esto sería otra razón para evitar la forma:

from module import * 
Cuestiones relacionadas