¿Qué pasaría si dos módulos de importación de cada uno de los otros?

Generalizar el problema, ¿qué acerca de la cíclica de las importaciones en Python?

  • Véase también stackoverflow.com/questions/158268/…
  • también sólo como una referencia, parece circular las importaciones están permitidos en python 3.5 (y probablemente más), pero no 3.4 (y probablemente más abajo).
  • Estoy usando python 3.7.2 y sigo teniendo un error en tiempo de ejecución debido a las dependencias circulares.
InformationsquelleAutor Xolve | 2009-04-13

12 Comentarios

  1. 252

    No era realmente una buena discusión sobre esto en comp.lang.python el año pasado. Contesta a su pregunta bastante bien.

    De las importaciones es bastante sencillo en realidad. Sólo recuerde lo siguiente:

    ‘importar’ y ‘de xxx de importación yyy» son instrucciones ejecutables. La ejecución de
    cuando la ejecución del programa llegue a esa línea.

    Si un módulo no está en sys.los módulos, luego de una importación, se crea el nuevo módulo
    la entrada en sys.módulos y, a continuación, ejecuta el código en el módulo. No
    devolver el control al módulo hasta que la ejecución se ha completado.

    Si un módulo no existe en sys.los módulos, a continuación, una importación simplemente devuelve que
    módulo de si o no se ha terminado de ejecutar. Esa es la razón por la que
    cíclico de las importaciones puede devolver los módulos que aparecen en la parte vacía.

    Finalmente, la ejecución de secuencia de comandos se ejecuta en un módulo denominado __principal__, la importación de
    la secuencia de comandos en su propio nombre, se creará un nuevo módulo ajenos a
    __main__.

    Que tomar mucho juntos y usted no debería tener sorpresas cuando la importación de
    los módulos.

    • NB: Circular de las importaciones semántica han cambiado en Python3!
    • Podría usted ampliar este comentario, por favor? ¿Cómo específicamente han cambiado?
    • A partir de ahora, la única referencia a circular las importaciones en python3 «¿Qué hay de nuevo?» páginas es en el 3,5 uno. Dice «Circular de las importaciones relacionado con las importaciones son ahora compatibles». @meawoppl has encontrado nada más de lo que no aparece en estas páginas?
    • Son def. no se admite en 3.0-3.4. O, al menos, la semántica para el éxito son diferentes. He aquí una sinopsis que he encontrado que dosn no mencionar el 3.5 cambios. gist.github.com/datagrok/40bf84d5870c41a77dc6
    • Por favor, usted puede ampliar esta «Finalmente, la ejecución de secuencia de comandos se ejecuta en un módulo denominado principal, la importación de la secuencia de comandos en su propio nombre, se creará un nuevo módulo ajenos a principal.». Por lo que permite decir que el archivo es un.py y cuando se ejecuta como principal punto de entrada, itsbthe principal ahora si que tiene un código como de una importación de una variable. Luego será el mismo archivo ‘un.py’ se cargan en el sistema de módulos de mesa? Así que, ¿significa que si se ha de decir de la impresión de la declaración, a continuación, se ejecutará dos veces? Una vez que el archivo principal y otra vez cuando la importación se encuentra?
  2. 260

    Si usted import foo dentro de bar y import bar dentro de foo, funcionará bien. Por el momento nada en realidad se ejecuta, tanto de los módulos será completamente cargado y tiene referencias a cada uno de los otros.

    El problema es cuando en lugar de hacer from foo import abc y from bar import xyz. Porque ahora cada módulo requiere el otro módulo para ya ser importados (de modo que el nombre le va a importar existe) antes de que puedan ser importados.

    • Parece que from foo import * y from bar import * va a funcionar.
    • Compruebe el editar el post anterior con a.py/b.py. Él no utiliza from x import y, y aún así obtiene la circular de error de importación
    • Esto no es totalmente cierto. Como de importación * de, si se intenta acceder a un elemento en la circular de importación, en el nivel superior, así que antes de que finalice la secuencia de comandos se ejecuta, entonces usted va a tener el mismo problema. Por ejemplo, si está instalando un paquete global en un paquete de otro, y ambos son el uno del otro. Yo estaba haciendo esto para crear un descuidado de fábrica para un objeto de la clase base donde ese objeto podría ser uno de un número de subclases y el uso de código no necesita ser consciente de qué era en realidad la creación.
    • De verdad que no. Que sólo importan los nombres que están disponibles cuando el import instrucción se ejecuta. Para que no de error, pero usted no puede conseguir todas las variables que usted espera.
    • Nota, si no from foo import * y from bar import *, todo lo ejecutado en el foo está en la fase de inicio de bar, y las funciones reales en bar aún no ha sido definido…
  3. 95

    Cíclico de las importaciones de terminar, pero debe tener cuidado de no utilizar el cíclicamente-módulos importados durante la inicialización de módulos.

    Considerar los siguientes archivos:

    una.py:

    print "a in"
    import sys
    print "b imported: %s" % ("b" in sys.modules, )
    import b
    print "a out"

    b.py:

    print "b in"
    import a
    print "b out"
    x = 3

    Si usted ejecuta una.py, obtendrá el siguiente:

    $ python a.py
    a in
    b imported: False
    b in
    a in
    b imported: True
    a out
    b out
    a out

    En el segundo de importación de b.py (en la segunda a in), el intérprete de Python no importa b de nuevo, porque ya existe en el módulo de dict.

    Si intenta obtener acceso a b.x de a durante la inicialización de módulos, usted recibirá un AttributeError.

    Agregar la siguiente línea a.py:

    print b.x

    Entonces, el resultado es:

    $ python a.py
    a in                    
    b imported: False
    b in
    a in
    b imported: True
    a out
    Traceback (most recent call last):
      File "a.py", line 4, in <module>
        import b
      File "/home/shlomme/tmp/x/b.py", line 2, in <module>
        import a
     File "/home/shlomme/tmp/x/a.py", line 7, in <module>
        print b.x
    AttributeError: 'module' object has no attribute 'x'

    Esto es debido a que los módulos se ejecutan en la importación y en el momento b.x se tiene acceso a la línea de x = 3 no se ha ejecutado aún, lo que sólo ocurrirá después de b out.

    • este gran medida explica el problema, pero ¿y la solución? ¿cómo podríamos correctamente la importación y la impresión de x? la otra solución anterior no funciona para mí
  4. 25

    Como otras respuestas describir este patrón es aceptable en python:

    def dostuff(self):
         from foo import bar
         ...

    Que va a evitar la ejecución de la sentencia de importación cuando el archivo es importado por otros módulos. Sólo si existe una lógica circular de la dependencia, se producirá un error.

    La mayoría de Circular de las Importaciones no son en realidad lógica circular de las importaciones, pero en lugar de elevar ImportError errores, porque de la manera import() evalúa el nivel superior de las declaraciones de todo el archivo cuando se le llama.

    Estos ImportErrors casi siempre pueden evitarse si usted positivamente quiere que sus importaciones en la parte superior:

    Considerar esta circular de importación:

    Aplicación De Un

    # profiles/serializers.py
    
    from images.serializers import SimplifiedImageSerializer
    
    class SimplifiedProfileSerializer(serializers.Serializer):
        name = serializers.CharField()
    
    class ProfileSerializer(SimplifiedProfileSerializer):
        recent_images = SimplifiedImageSerializer(many=True)

    Aplicación B

    # images/serializers.py
    
    from profiles.serializers import SimplifiedProfileSerializer
    
    class SimplifiedImageSerializer(serializers.Serializer):
        title = serializers.CharField()
    
    class ImageSerializer(SimplifiedImageSerializer):
        profile = SimplifiedProfileSerializer()

    De David Beazleys excelente charla Módulos y Paquetes: Vive y Deja Morir! – PyCon 2015, 1:54:00, aquí es una manera de lidiar con la circular de las importaciones en python:

    try:
        from images.serializers import SimplifiedImageSerializer
    except ImportError:
        import sys
        SimplifiedImageSerializer = sys.modules[__package__ + '.SimplifiedImageSerializer']

    Este intenta importar SimplifiedImageSerializer y si ImportError es elevado, porque ya es importado, que se tire de la importcache.

    PS: tienes Que leer este post entero en David Beazley la voz.

    • ImportError no se produce si el módulo ya han sido importados. Los módulos pueden ser importados tantas veces como se quiera decir, «importación de una; la importación de un;» está bien.
  5. 8

    Tengo un ejemplo que me llamó la atención!

    foo.py

    import bar
    
    class gX(object):
        g = 10

    bar.py

    from foo import gX
    
    o = gX()

    main.py

    import foo
    import bar
    
    print "all done"

    En la línea de comandos: $ python main.py

    Traceback (most recent call last):
      File "m.py", line 1, in <module>
        import foo
      File "/home/xolve/foo.py", line 1, in <module>
        import bar
      File "/home/xolve/bar.py", line 1, in <module>
        from foo import gX
    ImportError: cannot import name gX
    • ¿Cómo arreglar esto? Estoy tratando de comprender circular de importación para solucionar un problema de mi propio que se ve es similar a lo que estás haciendo…
    • Errm… creo que he solucionado mi problema con este increíblemente feo hack. {{{ si no ‘foo.bar’ en sys.módulos: de foo importar bar demás: bar = sys.módulos[‘foo.bar’] }}} Personalmente, creo circular de las importaciones son una GRAN señal de advertencia sobre el mal diseño de código…
    • o usted podría mover import bar en foo.py a la final
    • Si bar y foo tanto debe utilizar gX, el ‘más limpio’ solución es poner gX en otro módulo y ambos tienen foo y bar de importación de ese módulo. (limpio en el sentido de que no hay oculto semántica dependencias.)
    • Tim tiene un buen punto. Básicamente es porque bar no puede incluso encontrar gX en el foo. la circular de importación está bien por sí mismo, pero es que gX no está definida cuando es importado.
  6. 4

    Estoy totalmente de acuerdo con pythoneer la respuesta aquí. Pero he tropezado en algún código que fue defectuosa con la circular de las importaciones y causó problemas al tratar de agregar la unidad de pruebas. Así que rápidamente parche sin necesidad de cambiar todo lo que puede resolver el problema haciendo una dinámica de importación.

    # Hack to import something without circular import issue
    def load_module(name):
        """Load module using imp.find_module"""
        names = name.split(".")
        path = None
        for name in names:
            f, path, info = imp.find_module(name, path)
            path = [path]
        return imp.load_module(name, f, path[0], info)
    constants = load_module("app.constants")

    De nuevo, esto no es una solución permanente, pero puede ayudar a alguien que quiere corregir un error de importación sin cambiar demasiado el código.

    Saludos!

  7. 4

    Módulo.py :

    import b
    print("This is from module a")

    Módulo b.py

    import a
    print("This is from module b")

    Ejecución del Módulo «a» de salida:

    >>> 
    'This is from module a'
    'This is from module b'
    'This is from module a'
    >>> 

    Es la salida de este 3 líneas, mientras que se suponía que era la salida de infinitival porque de la circular de la importación.
    Lo que sucede línea por línea mientras se ejecuta»Módulo» se indican aquí:

    1. La primera línea es import b. por lo que se visita módulo b
    2. La primera línea en el módulo b es import a. así que va a visitar el módulo de un
    3. La primera línea en el módulo a es import b pero tenga en cuenta que esta línea no se ejecuta de nuevo ya, debido a que cada archivo en python ejecutar una línea de importación por una vez, no importa donde o cuando se ejecuta. por lo que pasará a la siguiente línea y la impresión "This is from module a".
    4. Después de terminar de visitar todo el módulo a módulo b, todavía estamos en el módulo b. así que la próxima línea de impresión "This is from module b"
    5. Módulo b líneas se ejecutan completamente. así que vamos a volver a módulo a donde empezamos a módulo b.
    6. de importación de la línea b se han ejecutado y que ya no se ejecuta de nuevo. la siguiente línea de impresión "This is from module a" y el programa estará terminado.
  8. 1

    Circular de las importaciones puede ser confuso debido a la importación de hace dos cosas:

    1. se ejecuta el módulo importado código
    2. añade módulo importado a la importación de módulo global de la tabla de símbolos

    El primero se realiza sólo una vez, mientras que el segundo, en cada declaración de importación. Circular de importación crea la situación de que cuando la importación módulo utiliza importados uno parcialmente con el código ejecutado. En consecuencia, no va a ver los objetos creados después de la declaración de importación. Siguiente ejemplo de código se muestra.

    Circular de las importaciones no son el final del mal que debe evitarse a toda costa. En algunos marcos de trabajo como Matraz de ellos son bastante naturales y el ajuste de su código para eliminarlas no hacer que el código sea mejor.

    main.py

    print 'import b'
    import b
    print 'a in globals() {}'.format('a' in globals())
    print 'import a'
    import a
    print 'a in globals() {}'.format('a' in globals())
    if __name__ == '__main__':
        print 'imports done'
        print 'b has y {}, a is b.a {}'.format(hasattr(b, 'y'), a is b.a)

    b.by

    print "b in, __name__ = {}".format(__name__)
    x = 3
    print 'b imports a'
    import a
    y = 5
    print "b out"

    una.py

    print 'a in, __name__ = {}'.format(__name__)
    print 'a imports b'
    import b
    print 'b has x {}'.format(hasattr(b, 'x'))
    print 'b has y {}'.format(hasattr(b, 'y'))
    print "a out"

    python main.py salida con los comentarios

    import b
    b in, __name__ = b    # b code execution started
    b imports a
    a in, __name__ = a    # a code execution started
    a imports b           # b code execution is already in progress
    b has x True
    b has y False         # b defines y after a import,
    a out
    b out
    a in globals() False  # import only adds a to main global symbol table 
    import a
    a in globals() True
    imports done
    b has y True, a is b.a True # all b objects are available
  9. 1

    He resuelto el problema de la siguiente manera, y funciona bien sin ningún error.
    Considere dos archivos a.py y b.py.

    He añadido esto a a.py y funcionó.

    if __name__ == "__main__":
            main ()

    una.py:

    import b
    y = 2
    def main():
        print ("a out")
        print (b.x)
    
    if __name__ == "__main__":
        main ()

    b.py:

    import a
    print ("b out")
    x = 3 + a.y

    La salida que se obtiene es

    >>> b out 
    >>> a out 
    >>> 5
  10. 0

    Hay una gran cantidad de respuestas aquí. Mientras que generalmente hay soluciones rápidas al problema, algunos de los cuales se sienten más python que otros, si usted tiene el lujo de hacer algunas de refactorización, otro enfoque es analizar la organización de su código, y tratar de eliminar la dependencia circular. Usted puede encontrar, por ejemplo, que usted tiene:

    Un archivo.py

    from b import B
    
    class A:
        @staticmethod
        def save_result(result):
            print('save the result')
    
        @staticmethod
        def do_something_a_ish(param):
            A.save_result(A.use_param_like_a_would(param))
    
        @staticmethod
        def do_something_related_to_b(param):
            B.do_something_b_ish(param)

    Archivo b.py

    from a import A
    
    class B:
        @staticmethod
        def do_something_b_ish(param):
            A.save_result(B.use_param_like_b_would(param))

    En este caso, solo el movimiento de un método estático en un archivo separado, decir c.py:

    Archivo c.py

    def save_result(result):
        print('save the result')

    permitirá la eliminación de la save_result a Un método de una, y por lo tanto permitir la eliminación de la importación de Una de a en b:

    Refactorizar un Archivo.py

    from b import B
    from c import save_result
    
    class A:
        @staticmethod
        def do_something_a_ish(param):
            A.save_result(A.use_param_like_a_would(param))
    
        @staticmethod
        def do_something_related_to_b(param):
            B.do_something_b_ish(param)

    Refactorizado el Archivo b.py

    from c import save_result
    
    class B:
        @staticmethod
        def do_something_b_ish(param):
            save_result(B.use_param_like_b_would(param))

    En resumen, si usted tiene una herramienta (por ejemplo, pylint o PyCharm) que informa sobre los métodos que pueden ser estáticos, acaba de lanzar un staticmethod decorador en ellos podría no ser la mejor manera para silenciar la alerta. Aunque el método parece estar relacionado con la clase, podría ser mejor por separado, especialmente si usted tiene varias estrechamente relacionados con los módulos que podrían tener la misma funcionalidad y desea practicar en SECO principios.

  11. -1

    Esta podría ser otra solución, trabajó para mí.

    def MandrillEmailOrderSerializer():
    from sastaticketpk.apps.flights.api.v1.serializers import MandrillEmailOrderSerializer
    return MandrillEmailOrderSerializer
    
    email_data = MandrillEmailOrderSerializer()(order.booking).data
  12. -2

    Ok, creo que tengo una genial solución.
    Digamos que usted tiene el archivo a y archivo b.
    Usted tiene un def o un class en el archivo b que desea utilizar en el módulo a, pero tiene algo, ya sea un def, class, o una variable de archivo a que usted necesita en su definición o de la clase en el archivo de b.
    Lo que puedes hacer es, en la parte inferior de archivo a, después de llamar a la función o clase en el archivo de a que se necesita en el archivo b, pero antes de llamar a la función o clase de archivo b que usted necesita para archivo a, decir import b
    Entonces, y aquí está el parte clave, en todas las definiciones o las clases en el archivo b que necesita el def o class de archivo a (vamos a llamar a CLASS), usted dice from a import CLASS

    Esto funciona porque puede importar el archivo de b sin Python se ejecuta cualquiera de las declaraciones de importación en el archivo b, y así eludir cualquier circular de las importaciones.

    Por ejemplo:

    De archivo:

    class A(object):
    
         def __init__(self, name):
    
             self.name = name
    
    CLASS = A("me")
    
    import b
    
    go = B(6)
    
    go.dostuff

    Archivo b:

    class B(object):
    
         def __init__(self, number):
    
             self.number = number
    
         def dostuff(self):
    
             from a import CLASS
    
             print "Hello " + CLASS.name + ", " + str(number) + " is an interesting number."

    Voila.

    • from a import CLASS en realidad no omitir la ejecución de todo el código en un.py. Yo creo que esto es lo que realmente está sucediendo aquí:
    • from a import CLASS en realidad no omitir la ejecución de todo el código en un.py. Esto es lo que sucede realmente: (1) Todo el código en un.py se ejecute como un módulo especial «__main__». (2) En import b, el código de nivel superior en b.py se ejecute (definición de la clase B) y, a continuación, se devuelve el control a «__main__». (3) «__main__» al final, pasa el control a go.dostuff(). (4) cuando dostuff() viene a import a, se ejecuta todo el código en un.py nuevo, esta vez como el módulo «a»; a continuación, se importa la CLASE de objeto desde el nuevo módulo «a». Así que, en realidad, esto podría funcionar igual de bien si se utiliza import a en cualquier lugar.b.py.

Dejar respuesta

Please enter your comment!
Please enter your name here