Python: ¿Cuál es el punto de usar "importar"?

8

No tengo muy claro este aspecto. Digamos que tiene un montón de archivos .py que son sus propios módulos separados.

¿Por qué cada archivo .py necesita importar los otros cuando usan esa clase? O ellos? Porque estaba bastante seguro de que otros lenguajes (Java, por ejemplo), no requerían importación al referirme a clases / archivos en el mismo directorio. Podría estar equivocado.

Kaitlyn Mcmordie
fuente

Respuestas:

8

En pocas palabras, esa es la forma en que fue diseñado. Usted mencionó Java como un ejemplo contrario: los diseñadores del lenguaje Java querían hacer que la carga de clases sea algo implícita, por lo que verifican el mismo directorio antes de lanzar ClassNotFound. Fuera de eso, debes calificar, al igual que en Python.

Como dijo Tom Anderson, C hace lo mismo que Python, y es un lenguaje compilado. Tal vez la naturaleza interpretada del lenguaje tuvo algo que ver con la decisión final (en cuanto a rendimiento, explicidad, etc.), pero al final depende del desarrollador.

Michael K
fuente
No estoy seguro de que "esa es la forma en que fue diseñado" realmente responda a esta pregunta.
Winston Ewert
2
-1: No sé Python bien, pero mi entendimiento es que usted tiene que importar un paquete para su uso nada en ella en Python. En Java, técnicamente nunca tiene que usar declaraciones de importación; simplemente puede escribir los nombres completos y calificados de las clases, etc. en otros paquetes.
compman
1
La calificación es resolver la ruta a un objeto (clase, función, lo que sea). Si es hecho por importaciones o calificadores de sintaxis es irrelevante.
Michael K
3

Debido a que Python se interpreta, todo lo que importa está disponible en el indicador. Java (y C ++) tiene un paso de compilación y enlace que puede buscar e incluir solo funciones que se utilizan

Si todo se importara automáticamente, habría miles de funciones y variables y sería imposible escribir algo sin colisionar con una.

editar: Ok, es un poco más que simplemente compilado vs interpretado. Python pretende ser un lenguaje de "baterías incluidas": hay bibliotecas disponibles para hacer casi todo. Dado que solo usará una pequeña fracción de esos, debe haber una forma de organizarlos para que solo incluya los que necesita.

La importación desde la sintaxis es inteligente porque puede importar toda la biblioteca y mantener nombres totalmente calificados similares a Java o puede importar funciones específicas (o todas las funciones) en el espacio de nombres local

>>>import math
>>> math.sin(0)  #no confusion with any other 'sin'

>>> from math import sin  # or import *
>>> sin(0) # makes equations with sin shorter and simpler

La segunda razón es especialmente importante en un lenguaje dinámico como Python. Como no tiene que definir variables antes de usarlas, sería difícil para el entorno determinar si sines una función matemática o una variable suya en un intérprete.

Martin Beckett
fuente
No lo entiendo ... ¿Podrías explicarlo por un novato? :(
Chuck Testa
@ChuckTesta Para comprender completamente la diferencia discutida en esta respuesta, debe comprender la diferencia entre los idiomas compilados e interpretados: esta publicación de blog lo resume en términos bastante simples: blog.julipedia.org/2004/07/…
Bob
8
La diferencia no tiene absolutamente nada que ver con la interpretación o la compilación. Podría escribir un compilador de Python y tendría que funcionar exactamente de la misma manera que el intérprete de Python. La diferencia es simplemente que los diseñadores de Java (por ejemplo) decidieron agregar la carga implícita de clases de otros archivos, y los diseñadores de Python no lo hicieron. Tenga en cuenta que C está compilado, pero tiene esencialmente las mismas reglas que Python: no puede usar una función de otro archivo a menos que #incluya un encabezado y vincule la biblioteca correcta.
Tom Anderson
2
El punto es válido: la carga implícita de clases tendría un gran costo de tiempo de ejecución en un lenguaje interpretado
Simon Bergot
1
@ Simon, ¿por qué tendría un gran costo de tiempo de ejecución?
Winston Ewert
1

Imagina que tienes este código en python:

foo = MyObject()
fo.bar()

Obviamente, tenemos un error tipográfico y fodebería haberlo sido foo. En este momento, Python dice:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'fo' is not defined

Pero con una carga de clase implícita podría decir:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named fo

lo cual sería confuso Peor aún, si escribiste mal el nombre de una variable que resultó ser el nombre de un módulo, obtendrás un error aún más confuso al tratar de tratar ese módulo como si fuera tu variable. Python no puede decir si algo es un nombre de clase, objeto o lo que sea.

Java, por otro lado, creo que puede deducir de la sintaxis si cierto identificador se refiere a una clase u otra cosa. Por lo tanto, no tiene problemas para generar un mensaje de error apropiado.

En general, se ajusta a la filosofía de Python de ser explícito en lugar de implícito. Calculan que es mejor importar explícitamente un módulo en lugar de importarlo automáticamente. El problema del mensaje de error es un factor que influye en la decisión.

Algunos han sugerido que habría un gran costo de tiempo de ejecución para las importaciones implícitas. No lo creo. Lo que pasa es algo como esto:

  1. Código de operación LOAD_GLOBAL invocado con el nombre "foo"
  2. diccionario global verificado para "foo"
  3. diccionario incorporado verificado para "foo"
  4. Si se encuentra foo, guárdelo en globals y continúe
  5. Si no se encuentra, aumente NameError

Para soportar la carga implícita de módulos, podríamos hacer:

  1. Código de operación LOAD_GLOBAL invocado con el nombre "foo"
  2. diccionario global verificado para "foo"
  3. diccionario incorporado verificado para "foo"
  4. Si lo anterior falla, intente import foo
  5. Si se encuentra foo, guárdelo en globals y continúe
  6. Si no se encuentra, aumente NameError

La primera vez que se usa el módulo, tomaría un poco más de tiempo porque primero tiene que buscar en otros diccionarios. Pero esa es solo la primera vez, y no debería ser significativa en términos de tiempo de ejecución de todo el programa.

Habría un costo significativo, en el caso de nombres de variables mal escritos. Cuando ocurren, Python perdería el tiempo leyendo el disco tratando de encontrar el módulo. Pero si eso sucede, su programa está a punto de morir con un rastreo de todos modos y el rendimiento no es una gran preocupación.

Winston Ewert
fuente
1

Hay algunas diferencias importantes entre Python y Java; mientras que Java tiene una regla de "una clase por archivo", Python no. Además, no todo en Python es una clase.

Por lo tanto, un módulo puede tener clases, funciones y simplemente variables antiguas, generalmente relacionadas de alguna manera (como funciones aleatorias random, rutinas matemáticas math, constantes de cadenas string, etc.).

Si desea acceder a cualquiera de las clases / funciones / variables desde un módulo en particular, primero debe importarlo.

¿Por qué es esto algo bueno?

  • Mantiene los espacios de nombres de módulos limpios (no saturados con nombres que nunca usará)
  • Más fácil rastrear al módulo apropiado cuando algo sale mal
  • Le permite usar nombres sin temor a un error, ya que el nombre está en uso, o puede cambiar el nombre que ya está en uso (puede tener math.siny sus propias sinfunciones)
  • Ayuda a aclarar la estructura del programa.
Ethan Furman
fuente
1

Uno de los conceptos más importantes en Python es el de los espacios de nombres ( import thisen el momento oportuno para averiguar cuáles son los demás). Sé que los espacios de nombres también existen en otros idiomas, pero en Python solo tienes acceso al espacio de nombres actual, que es lo que está definido en el módulo actual. Para obtener acceso a otros identificadores, debe importarlos al espacio de nombres actual: ya sea importando su módulo contenedor (la import foosintaxis) o los nombres mismos ( from foo import bar).

Daniel Roseman
fuente