Pythonic способ разрешения круговых операторов импорта? - PullRequest
31 голосов
/ 21 апреля 2011

Я просто унаследовал некоторый код, который меня беспокоит: на нашем сайте есть тестовая библиотека, полная классов, соответствующих веб-страницам, и у каждого класса веб-страниц есть методы для автоматизации функций на этой странице.

Тамметоды для щелчка по ссылке между страницами, которая возвращает класс связанной страницы.Вот упрощенный пример:

Файл homePageLib.py:

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()

Файл 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()

Это позволяет файлу сценария нажимать на страницы иполучить объект как возвращаемое значение от этого метода, то есть автору сценария не придется создавать экземпляры новых страниц при перемещении по сайту.(Мне кажется, что это странный дизайн, но я не могу точно понять, почему, кроме этого, кажется странным иметь метод с именем 'clickSomeLink' и возвращать объект полученной страницы.)

Следующий скрипт иллюстрирует, как скрипт будет перемещаться по сайту: (я вставил print page, чтобы показать, как изменяется объект страницы)

Файл скрипта:

from homePageLib import HomePage

page = HomePage()    
print page
page = page.clickCalendarLink()
print page
page = page.clickHomePageLink()
print page

, который производитследующий вывод:

<homePageLib.HomePage object at 0x00B57570>
Click Calendar link
<calendarLib.CalendarPage object at 0x00B576F0>
Click Home Page link
<homePageLib.HomePage object at 0x00B57570>

Итак, часть этого, что мне особенно неприятно, это строки from ____ import ____, которые заканчиваются повсюду.Они мне кажутся плохими по следующим причинам:

  1. Я всегда придерживался соглашения помещать все операторы импорта в начало файла.
  2. Поскольку их может быть несколькоссылки на страницу, это приводит к одной и той же строке кода from foo import bar в нескольких местах в файле.

Проблема в том, что если поместить эти операторы импорта в верхнюю часть страницы, мы получим ошибки импорта, потому что (согласно этому примеру) HomePage импортирует CalendarPage и наоборот:

Файл 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()

Файл 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()

Это приводит к следующей ошибке:

>>> 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

(советы по улучшениюотформатировать вывод Python?)

Вместо того, чтобы увековечивать этот стиль, я бы хотел найти лучший способ.Есть ли Pythonic способ иметь дело с циклическими зависимостями, подобными этому, и при этом сохранять операторы импорта в верхней части файла?

Ответы [ 2 ]

57 голосов
/ 21 апреля 2011

Для устранения этих конструкций обычно используются такие методы, как Внедрение зависимостей .

Однако исправить эту ошибку довольно просто:

В calendarLib.py:

import homePageLib

class CalendarPage(object):
    def clickHomePageLink(self):
        [...]
        return homePageLib.HomePage()

Код на уровне модуля выполняется во время импорта.Использование синтаксиса from [...] import [...] требует, чтобы модуль был полностью инициализирован для успешного завершения.

Простой import [...] этого не делает, потому что нет доступа к символам, что нарушает цепочку зависимостей.

2 голосов
/ 06 апреля 2016

Пожалуйста, прочитайте ответ Себастьяна для подробного объяснения.Этот подход был предложен Дэвидом Бизли (David Beazley) в PyCon

. Попробуйте позиционировать импорт сверху, как показано нижене удалось, попробую загрузить его из кеша

...