¿Por qué importar cuando necesitas usar el nombre completo?

En Python, si necesita un módulo de un paquete diferente, debe importarlo. Viniendo de un fondo de Java, eso tiene sentido.

import foo.bar 

Lo que no tiene sentido, sin embargo, es ¿por qué necesito usar el nombre completo cuando quiero usar la barra? Si quisiera usar el nombre completo, ¿por qué necesito importar? ¿El uso del nombre completo no describe inmediatamente a qué módulo me dirijo?

Simplemente parece un poco redundante tenerlo from foo import bar cuando eso es lo que debería estar haciendo import foo.bar . También un poco vago por qué tuve que importar cuando iba a usar el nombre completo.

La cosa es que, aunque la statement de import de Python está diseñada para parecerse a la de Java, hacen cosas completamente diferentes bajo el capó. Como saben, en Java una statement de import es realmente poco más que una sugerencia para el comstackdor. Básicamente, establece un alias para un nombre de clase completamente calificado. Por ejemplo, cuando escribes

 import java.util.Set; 

le dice al comstackdor que a lo largo de ese archivo, cuando escribe Set , quiere decir java.util.Set . Y si escribe s.add(o) donde s es un objeto de tipo Set , el comstackdor (o mejor dicho, el enlazador) se apaga y encuentra el método add en Set.class y pone una referencia a él.

Pero en Python,

 import util.set 

(que es un módulo inventado, por cierto) hace algo completamente diferente. Vea, en Python, los paquetes y los módulos no son solo nombres , son objetos reales, y cuando escribe util.set en su código, eso le indica a Python que acceda a un objeto llamado util y busque un atributo en su set denominado. El trabajo de la statement de import de Python es crear ese objeto y atributo. La forma en que funciona es que el intérprete busca un archivo llamado util/__init__.py , usa el código para definir las propiedades de un objeto y lo vincula al nombre util . De manera similar, el código en util/set.py se usa para inicializar un objeto que está vinculado a util.set . Hay una función llamada __import__ que se encarga de todo esto, y de hecho, la statement de import util.set es básicamente equivalente a

 util = __import__('util.set') 

El punto es que, cuando importas un módulo de Python, lo que obtienes es un objeto correspondiente al paquete de nivel superior, util . Para obtener acceso a util.set debes pasar por eso, y es por eso que parece que necesitas usar nombres completos en Python.

Hay maneras de evitar esto, por supuesto. Dado que todas estas cosas son objetos, un enfoque simple es simplemente vincular util.set a un nombre más simple, es decir, después de la statement de import , puede tener

 set = util.set 

y a partir de ese momento puede usar set donde, de lo contrario, habría escrito util.set . (Por supuesto, esto oculta la clase de set incorporada, así que no recomiendo usar el set nombres). O, como se menciona en al menos otra respuesta, podría escribir

 from util import set 

o

 import util.set as set 

Esto sigue importando el paquete util con el módulo set en él, pero en lugar de crear una variable util en el ámbito actual, crea un set variables que hace referencia a util.set . Detrás de las escenas, esto funciona algo así como

 _util = __import__('util', fromlist='set') set = _util.set del _util 

en el primer caso, o

 _util = __import__('util.set') set = _util.set del _util 

en el segundo (aunque ambas formas hacen esencialmente lo mismo). Este formulario es semánticamente más parecido a lo que hace la statement de import de Java: define un alias ( set ) a algo que normalmente solo sería accesible por un nombre util.set ( util.set ).

Puedes acortarlo, si quieres:

 import foo.bar as whateveriwant 

El uso del nombre completo evita que dos paquetes con los submódulos del mismo nombre se obstruyan entre sí.

Hay un módulo en la biblioteca estándar llamado io :

 In [84]: import io In [85]: io Out[85]:  

También hay un módulo en scipy llamado io :

 In [95]: import scipy.io In [96]: scipy.io Out[96]:  

Si desea usar ambos módulos en el mismo script, entonces los espacios de nombres son una forma conveniente de distinguir los dos.

 In [97]: import this The Zen of Python, by Tim Peters ... Namespaces are one honking great idea -- let's do more of those! 

en Python, la importación no solo indica que podrías usar algo. La importación realmente ejecuta código en el nivel de módulo. Puede pensar que la importación es el momento en el que las funciones se “interpretan” y se crean. Cualquier código que se encuentre en el nivel _____init_____.py o que no esté dentro de una función o definición de clase sucederá entonces.

La importación también hace una copia barata del espacio de nombres de todo el módulo y lo coloca dentro del espacio de nombres del archivo / módulo / donde sea que se importe. Luego, un IDE tiene una lista de las funciones que podría estar comenzando a escribir para completar el comando.

Parte de la filosofía de Python es explícita es mejor que implícita . Python podría importar automáticamente la primera vez que intentes acceder a algo desde un paquete, pero eso no es explícito.

También supongo que la inicialización del paquete sería mucho más difícil si las importaciones fueran automáticas, ya que no se haría de manera consistente en el código.

Estás un poco confundido acerca de cómo funcionan las importaciones de Python. (Yo también lo estaba cuando empecé). En Python, no puedes simplemente referirte a algo dentro de un módulo por el nombre completo, a diferencia de Java; TIENE QUE importar el módulo primero, independientemente de cómo piense referirse al artículo importado. Intente escribir math.sqrt(5) en el intérprete sin importar math or math.sqrt primero y ver qué sucede.

De todos modos … la razón por la que import foo.bar requiere que uses foo.bar lugar de solo bar es para evitar conflictos accidentales en el espacio de nombres. Por ejemplo, ¿qué sucede si import foo.bar y luego import baz.bar ?

Por supuesto, puede elegir import foo.bar as bar (es decir, alias), pero si lo está haciendo, también puede utilizar la from foo import bar . (EDIT: excepto cuando desee importar métodos y variables. Luego debe usar la syntax from ... import ... Esto incluye las instancias en las que desea importar un método o variable sin alias, es decir, no puede simplemente import foo.bar si la bar es un método o variable.)

Aparte de en Java, en Python, import foo.bar declara que va a utilizar la cosa a la que hace referencia foo.bar .

Esto coincide con la filosofía de Python de que explícito es mejor que implícito. Hay más lenguajes de progtwigción que hacen que las dependencias entre módulos sean más explícitas que Java, por ejemplo, Ada.

El uso del nombre completo permite desambiguar definiciones con el mismo nombre proveniente de diferentes módulos.

No tienes que usar el nombre completo. Prueba uno de estos

 from foo import bar import foo.bar as bar import foo.bar bar = foo.bar from foo import * 

Algunas razones por las cuales las importaciones explícitas son buenas:

  • Ayudan a señalar a los seres humanos y las herramientas de qué paquetes depende su módulo.
  • Evitan la sobrecarga de determinar dinámicamente qué paquetes deben cargarse (y posiblemente comstackrse) en tiempo de ejecución.
  • Ellos (junto con sys.path) distinguen sin ambigüedad los símbolos con nombres en conflicto de diferentes espacios de nombres.
  • Le dan al progtwigdor algo de control sobre lo que ingresa al espacio de nombres dentro del cual está trabajando.