Pythonic方法解决循环导入语句?

时间:2011-04-21 19:37:41

标签: python pageobjects

我刚刚继承了一些让我感到不安的代码:有一个测试库,其中包含与我们网站上的网页相对应的类,每个网页类都有自动化该页面功能的方法。

有一些方法可以点击页面之间的链接,返回链接页面的类。这是一个简化的例子:

文件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. 我总是将所有import语句放在文件的顶部。
  2. 由于页面可能有多个链接,因此会在文件的多个位置生成相同的from foo import bar代码行。
  3. 问题是,如果我们将这些import语句放在页面顶部,就会出现导入错误,因为(根据此示例),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方法来处理像这样的循环依赖,并仍然将import语句保留在文件的顶部?

2 个答案:

答案 0 :(得分:57)

解决这些结构通常涉及Dependency Injection等技术。

然而,修复此错误相当简单:

在calendarLib.py中:

import homePageLib

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

模块级别的代码在导入时执行。使用from [...] import [...]语法需要完全初始化模块才能成功。

简单的import [...]没有,因为没有访问符号,从而打破了依赖链。

答案 1 :(得分:1)

请阅读Sebastian's answer了解详细说明。这种方法是由David Beazley在PyCon

中提出的

尝试将导入定位在顶部,如下所示

try:
    from homePageLib import HomePage
except ImportError:
    import sys
    HomePage = sys.modules[__package__ + '.HomePage']

这将尝试导入您的HomePage,如果失败,将尝试从缓存中加载