subplot python
¿Forma pitónica de resolver sentencias de importación circulares? (3)
Por favor, lea la respuesta de Sebastian para una explicación detallada. Este enfoque fue propuesto por David Beazley en PyCon
Intenta posicionar las importaciones en la parte superior así.
try:
from homePageLib import HomePage
except ImportError:
import sys
HomePage = sys.modules[__package__ + ''.HomePage'']
Esto intentará importar tu HomePage
y si falla, intentará cargarlo desde el caché
Acabo de heredar un código que me inquieta: hay una biblioteca de pruebas, llena de clases correspondientes a páginas web en nuestro sitio, y cada clase de página web tiene métodos para automatizar la funcionalidad en esa página.
Existen métodos para hacer clic en el enlace entre páginas, que devuelve la clase de la página vinculada. Aquí hay un ejemplo simplificado:
Archivo homePageLib.py archivo:
class HomePage(object):
def clickCalendarLink(self):
# Click page2 link which navigates browswer to page2
print "Click Calendar link"
# Then returns the page2 object
from calendarLib import CalendarPage
return CalendarPage()
Archivo calendarLib.py:
class CalendarPage(object):
def clickHomePageLink(self):
# Click page1 link which navigates browswer to page1
print "Click Home Page link"
# Then return the page2 object
from homePageLib import HomePage
return HomePage()
Esto permite que el archivo de script haga clic en las páginas y obtenga el objeto como un valor de retorno de ese método, lo que significa que el autor del script no tendrá que seguir creando una instancia de las páginas nuevas a medida que navegan por el sitio. (Siento que este es un diseño extraño, pero no puedo señalar exactamente por qué, aparte de eso, parece extraño tener un método llamado ''clickSomeLink'' y devolver un objeto de la página resultante).
La siguiente secuencia de comandos ilustra cómo una secuencia de comandos se desplazaría por el sitio: (inserté print page
para mostrar cómo cambia el objeto de la página)
Archivo de comandos:
from homePageLib import HomePage
page = HomePage()
print page
page = page.clickCalendarLink()
print page
page = page.clickHomePageLink()
print page
que produce el siguiente resultado:
<homePageLib.HomePage object at 0x00B57570>
Click Calendar link
<calendarLib.CalendarPage object at 0x00B576F0>
Click Home Page link
<homePageLib.HomePage object at 0x00B57570>
Entonces, la parte de esto que más me incomoda específicamente es la from ____ import ____
líneas que terminan por todas partes. Estos me parecen malos por las siguientes razones:
- Siempre he hecho una convención para poner todas las declaraciones de importación en la parte superior de un archivo.
- Como puede haber varios enlaces a una página, esto se traduce en el mismo que en la línea de código de la
from foo import bar
en varios lugares de un archivo.
El problema es que si ponemos estas declaraciones de importación en la parte superior de la página, obtendremos errores de importación, porque (como en este ejemplo), HomePage importa CalendarPage y viceversa:
Archivo homePageLib.py
from calendarLib import CalendarPage
class HomePage(object):
def clickCalendarLink(self):
# Click page2 link which navigates browswer to page2
print "Click Calendar link"
# Then returns the page2 object
return CalendarPage()
Archivo calendarLib.py
from homePageLib import HomePage
class CalendarPage(object):
def clickHomePageLink(self):
# Click page1 link which navigates browswer to page1
print "Click Home Page link"
# Then return the page2 object
return HomePage()
Esto resulta en el siguiente error:
>>> from homePageLib import HomePage
Traceback (most recent call last):
File "c:/temp/script.py", line 1, in ?
#Script
File "c:/temp/homePageLib.py", line 2, in ?
from calendarLib import CalendarPage
File "c:/temp/calendarLib.py", line 2, in ?
from homePageLib import HomePage
ImportError: cannot import name HomePage
(consejos sobre cómo formatear mejor la salida de python?)
En lugar de perpetuar este estilo, me gustaría encontrar una mejor manera. ¿Hay alguna forma en Pythonic de lidiar con dependencias circulares como esta y aún así mantener las declaraciones de importación en la parte superior del archivo?
Resolver estos constructos usualmente involucra técnicas como la inyección de dependencia .
Sin embargo, es bastante simple corregir este error:
En calendarLib.py:
import homePageLib
class CalendarPage(object):
def clickHomePageLink(self):
[...]
return homePageLib.HomePage()
El código a nivel de módulo se ejecuta en el momento de la importación. El uso de la sintaxis from [...] import [...]
requiere que el módulo se inicialice completamente para tener éxito.
Una simple import [...]
no lo hace, porque no se accede a ningún símbolo, rompiendo así la cadena de dependencia.
Sí. Refactorizar para romper las cosas en piezas más pequeñas e independientes.