2011-12-27 33 views
1

我在一個項目中做了一個相當有意思的導入方案,我想我可能在Python解釋器中發現了一個導致模塊導入兩次的錯誤。模塊導入兩次。 Python解釋器中可能存在的錯誤

這裏是我的測試項目是如何設置的:

  • /

    • Launcher.bat —項目就是從這裏跑。它啓動「使用Python 3.2可執行

    • 主/ __ init__.py —的__main__腳本主/ __ __初始化。py`,一個是推出 'Launcher.bat'

    • 主/ foo中。 PY —包含一個空類

    • 外部/ __ init__.py —腳本外部的「主」工程腳本,用來說明問題

./Launcher.bat

@echo off 
C:\Python32\python.exe main\__init__.py 
pause 

./main/__init__.py

from foo import Foo 
print("In 'main', Foo has id:", id(Foo)) 

# Add the directory from which 'Launcher.bat' was run, 
# which is not the same as the './main' directory 
# in which this script is located 
import sys 
sys.path.insert(1, '.') 


# This script will try to import class Foo, but in doing so 
# will casue the interpreter to import this './main/__init__.py' 
# script a second time. 
__import__('external') 

./main/foo.py

class Foo: 
    pass 

./external/__init__.py

from main.foo import Foo 
print("In 'external', Foo has id:", id(Foo)) 

所有這一切都將打印'Main script was imported'消息的兩倍。如果外部腳本導入任何其他腳本,那麼這些腳本也將被導入兩次。我只在Python 3.2上測試過。這是一個錯誤,還是我犯了一個錯誤?該方案的

輸出是:

在 '主',富具有ID:12955136
在 '主',富具有ID:12955136
在 '外部',富具有ID:12957456
按任意鍵繼續。 。 。

+0

它總是讓我笑聲明:我的代碼工作,python有一個bug:D – fabrizioM 2011-12-27 18:21:26

+0

@fabrizioM然後,你不能真正說你會期望Python導入相同的模塊兩次。我現在知道它爲什麼會發生,但我仍然認爲它不應該發生。 – 2011-12-27 18:24:23

回答

1

第一print是一種誤導:既然你不進口,但在執行第一次文件(__name__ == '__main__'成立),主要功能模塊只被導入一次。將起點移動到輔助文件中,或檢查__name__ == '__main__'

順便說一下,circularimport是一個壞主意。您應該解決循環導入(通過將foo移至專用庫)。或者,您可以使您的模塊可重入(即在添加它之前檢查當前目錄在sys.path中)。

+0

這不是一個循環導入的結果。我最初通過導入第三個文件「./main/foo.py」來發現這一點,這兩個文件都導入了./main/ \ __ init __。py和'./external/\ __ init __。py'。我注意到'foo.py'內定義的類在'main'腳本和'external'腳本之間有不同的'id()'值,這意味着腳本被導入了兩次。 (但你是對的,在第一個洞口這看起來像一個循環導入問題,我會解決這個問題。) – 2011-12-27 12:58:21

+0

@Paul Manta我期待着一個不包含循環導入的更新問題,而不是(只有'import'聲明) – phihag 2011-12-27 13:01:13

+0

@PaulManta糟糕,我忽略了另一件事情:你正在執行一個'main/__ init __。py'。因此,該模塊只需加載一次;第一印刷是誤導。更新了答案。 – phihag 2011-12-27 13:08:30

2

我不認爲這是一個錯誤。您應該詢問python-dev列表以獲取更權威的答案。您正在執行一次(當您運行腳本時)並導入一次(從外部),因此該行會打印兩次。它不會導入兩次。

但是,這是一個可怕的設置。這裏有很多風格違規。當然,有些僅用於演示目的,但仍然非常混亂。

  1. 您不應該使用包__init__.py文件作爲應該運行的文件。主入口點應該是一個導入包的腳本。
  2. 您不應該有一個導入模塊導入導入它的模塊。就像你外在的做主。
+0

我知道這是一個可怕的設置,我稱它爲自己做作。 :)這是出於演示目的,我試圖儘可能少的文件做到這一點。實際上,該模塊導入了兩次。如果比較'main'和'external'的''Foo''的'id()',你會發現它們是不同的。 – 2011-12-27 12:53:47

+1

@Paul Manta:有一個「main」導入,一個是main的_execution_。這解釋了爲什麼你有兩個版本的Foo被定義。當您執行腳本時,它不會被導入和緩存。爲了測試理論,創建一個空白的main/__ main__.py,並更改啓動腳本以執行「python -m main」。 – axw 2011-12-27 13:01:10

+0

類的id是與進口問題正交的。您可以在模塊中定義一個'Foo'類,導入另一個模塊'x'並擁有'x.Foo'。兩者都有不同的'id's。那是你的情況。 – 2011-12-27 13:05:32