Mod1.py

import mod2

class Universe:
    def __init__(self):
        pass
    def answer(self):
        return 42

u = Universe()
mod2.show_answer(u)

Mod2.py

#import mod1 -- not necessary
def show_answer(thing):
    print thing.answer()

Viniendo de un fondo C ++ tuve la sensación de que era necesario importar el módulo que contiene la definición de clase Universe antes de que la función show_answer funcione. Es decir. todo tenía que ser declarado antes de poder ser utilizado.

¿Estoy en lo cierto al pensar que esto no es necesario? Esto es escribir pato, ¿verdad? Entonces, si no se requiere una importación para ver los métodos de una clase, ¿al menos la necesitaría para la definición de la clase en sí y las funciones de nivel superior de un módulo?

En una secuencia de comandos que he escrito, incluso fui tan lejos como escribir una clase base para declarar una interfaz con un conjunto de métodos, y luego derivar clases concretas para heredar esa interfaz, pero creo que lo entiendo ahora, eso está mal en Python, y si un objeto tiene un método particular, ¿se verifica en tiempo de ejecución en el punto donde se realiza la llamada?

Me doy cuenta de que Python es así que mucho más dinámico que C ++, ¡me ha llevado un tiempo ver qué poco código necesitas escribir!

Creo que sé la respuesta a esta pregunta, pero solo quería obtener una aclaración y asegurarme de que estaba en el camino correcto.

ACTUALIZACIÓN: Gracias por todas las respuestas, creo que debería aclarar mi pregunta ahora:

¿Mod2.show_answer () necesita una importación (de cualquier descripción) para saber que esa cosa tiene un método llamado answer (), o se determina dinámicamente en tiempo de ejecución?

5
Steve Folly 22 jun. 2009 a las 18:35

6 respuestas

La mejor respuesta

import se trata de nombres, principalmente "nombres desnudos" que están vinculados en el nivel superior (nivel global AKA, nombres de nivel de módulo AKA) en un determinado módulo, digamos mod2. Cuando haya terminado import mod2, obtendrá el espacio de nombres mod2 como nombre disponible (nivel superior en su propio módulo, si está haciendo el import como nivel superior, como es más común, pero un import local dentro de una función haría mod2 una variable local de esa función, etc.); y, por lo tanto, puede utilizar mod2.foobar para acceder al nombre foobar que está vinculado al nivel superior en mod2. Si no necesita acceder a dichos nombres, no necesita import mod2 en su propio módulo.

4
Alex Martelli 22 jun. 2009 a las 15:06

En este caso tienes razón: a show_answer () se le da un objeto, al cual llama el método "respuesta". Mientras el objeto dado a show_answer () tenga dicho método, no importa de dónde provenga el objeto.

Sin embargo, si desea crear una instancia de Universe dentro de mod2, tendría que importar mod1, porque Universe no está en el espacio de nombres de mod2, incluso después de que mod2 haya importado mod2.

6
balpha 22 jun. 2009 a las 14:49

De hecho, de acuerdo con esta explicación, la circular import no funcionará la forma en que desea que funcione: si descomenta import mod1, el segundo módulo aún no sabrá acerca de Universe.

Creo que esto es bastante razonable. Si ambos archivos necesitan acceso al tipo de algún objeto específico, como Universe, tiene varias opciones:

  • si su programa es pequeño, solo use un archivo
  • si es grande, debe decidir si ambos archivos necesitan saber cómo se implementa Universe, tal vez pasar un objeto de tipo aún desconocido a show_answer está bien
  • si eso no funciona para usted, coloque Universe en un módulo separado y cárguelo primero.
1
ilya n. 22 jun. 2009 a las 15:03

No sé mucho sobre C ++, así que no puedo compararlo directamente, pero ...

import básicamente carga el otro script Python (mod2.py) en el script actual (el nivel superior de mod1.py). No es tanto un enlace, está más cerca de un eval

Por ejemplo, en Python'ish psuedo-code:

eval("mod2.py")

Es la misma que ..

from mod2 import *

..it ejecuta mod2.py y hace que las funciones / clases definidas sean accesibles en el script actual.

Ambos fragmentos anteriores le permitirían llamar a show_answer() (bueno, eval no funciona así, ¡así que lo llamé pseudocódigo!)

import mod2

... es básicamente lo mismo, pero en lugar de incorporar todas las funciones al "nivel superior", las trae al módulo mod2, por lo que debe llamar a show_answer haciendo ..

mod2.show_answer

¿Estoy en lo cierto al pensar que [la importación en mod2.py] no es necesaria?

Absolutamente. De hecho, si intenta importar mod1 desde mod2, obtiene un error de dependencia circular (ya que mod2 intenta importar mod1, etc.)

1
dbr 22 jun. 2009 a las 16:19

Importar en Python carga el módulo en el espacio de nombres dado. Como tal, es como si def show_answer realmente existiera en el módulo mod1.py. Debido a esto, mod2.py no necesita saber de la clase Universe y, por lo tanto, no necesita importar mod1 desde mod2.py.

1
AlbertoPL 22 jun. 2009 a las 15:08

Piense en importar más como el enlazador.
Con "import mod2" simplemente le está diciendo a python que puede encontrar la función en el archivo mod2.py

1
Martin Beckett 22 jun. 2009 a las 14:43