Python導入循環方法

  • 2020 年 1 月 23 日
  • 筆記

摘自:Python核心編程第二版:

12.8.5 導入循環

    實際上,在使用 Python 時, 你會發現是能夠導入循環的。 如果你開發了大型的 Python 工程, 那麼你很可能會陷入這樣的境地。 

    我們來看一個例子。 假定我們的產品有一個很複雜的命令行介面( command-line interface ,CLI)。 其中將會有超過一百萬的命令, 結果你就有了一個「超冗餘處理器」(overly massive handler,OMH)子集。 每加入一個新特性, 將有一到三條的新命令加入, 用於支援新的特性。 下邊是我們的omh4cli.py 腳本:

from cli4vof import cli4vof

# command line interface utility function

def cli_util():

    pass

# overly massive handlers for the command line interface

def omh4cli():

    :

        cli4vof()

    :

        omh4cli()

    假定大多控制器都要用到這裡的(其實是空的)工具函數。命令行介面的 OMH 都被封裝在 omh4cli() 函數里。 如果我們要添加一個新的命令, 那麼它會被調用。 

    現在這個模組不斷地增長, 一些聰明的工程師會決定把新命令放入到隔離的模組里, 在原始模 塊中只提供訪問新東西的鉤子。 這樣, 管理程式碼會變得更簡單, 如果在新加入內容中發現了 bug , 那麼你就不必在一個幾兆的 Python 文件里搜索。 

    在我們的例子中, 有一個興奮的經理要我們加入一個 "非常好的特性"。我們將創建一個新的 cli4vof.py 腳本, 而不是把新內容集成到omh4cli.py 里: 

import omh4cli 

# command-line interface for a very outstanding feature

def cli4vof():

    omh4cli.cli_util()

    前邊已經提到, 工具函數是每個命令必須的, 而且由於不能把程式碼從主控制器複製出來, 所以 我們導入了主模組, 在我們的控制器中添加對 omh , omh4cli() 的調用。 

    問題在於主控制器 omh4cli 會導入我們的 cli4vof 模組(獲得新命令的函數), 而 cli4vof 也會導入 omh4cli (用於獲得工具函數)。模組導入會失敗, 這是因為 Python 嘗試導入一個先前沒 有完全導入的模組:

$ python omh4cli.py 

Traceback (most recent call last):

File "omh4cli.py", line 3, in ? from cli4vof import cli4vof

File "/usr/prod/cli4vof.py", line 3, in ?

import omh4cli

File "/usr/prod/omh4cli.py", line 3, in ?

from cli4vof import cli4vof

ImportError: cannot import name cli4vof

    注意跟蹤返回消息中顯示的對 cli4vof 的循環導入。 問題在於要想調用工具函數, cli4vof 必 須導入 omh4cli 。 如果它不需要這樣做, 那麼 omh4cli 將會成功導入 cli4vof , 程式正常執行。 但在這裡, omh4cli 嘗試導入 cli4vof , 而 cli4vof 也試著導入 omh4cli 。 最後誰也不會完成 導入工作, 引發錯誤。 這只是一個導入循環的例子。 事實上實際應用中會出現更複雜的情況。

    解決這個問題幾乎總是移除其中一個導入語句。 你經常會在模組的最後看到 import 語句。作 為一個初學者, 你只需要試著習慣它們, 如果你以前遇到在模組底部的 import 語句,現在你知道是為什麼了。在我們的例子中, 我們不能把 import omh4cli 移到最後, 因為調用 cli4vof() 的時候 omh4cli() 名字還沒有被載入。

$ python omh4cli.py 

Traceback (most recent call last): File "omh4cli.py", line 3, in ? from cli4vof import

cli4vof

File "/usr/prod/cli4vof.py", line 7, in ?

import omh4cli

File "/usr/prod/omh4cli.py", line 13, in ?

omh4cli()

File "/usr/prod/omh4cli.py", line 11, in omh4cli cli4vof()

File "/usr/prod/cli4vof.py", line 5, in cli4vof omh4cli.cli_util()

NameError: global name 'omh4cli' is not defined

    我們的解決方法只是把 import 語句移到 cli4vof() 函數內部:

def cli4vof():

    import omh4cli

    omh4cli.cli_util()

    這樣, 從 omh4cli() 導入 cli4vof() 模組會順利完成, 在 omh4cli() 被調用之前它會被正 確導入。 只有在執行到 cli4vof.cli4vof() 時候才會導入 omh4cli 模組。