標籤:找不到 第一步 內建函數 sdn 使用 code ofo 說明 attr
原文連結:http://blog.csdn.net/lis_12/article/details/52883729
問題1
同一個目錄下,有兩個Python檔案,A.py,B.py
#A.pyfrom B import Dclass C(object): pass#B.pyfrom A import Cclass D(object): pass‘‘‘執行A.py結果:Traceback (most recent call last): File "A.py", line 4, in <module> from B import D File "B.py", line 4, in <module> from A import C File "A.py", line 4, in <module> from B import DImportError: cannot import name D‘‘‘
why?
from B import D的執行機制
可以利用sys.modules查看是否包含B模組,如查看os模組,輸入
>>> sys.modules[‘os’].
存在模組B
如果sys.modules有B這個鍵,就會擷取相對應的值,也就是modules對象,然後從模組B的__dict__列表中尋找並擷取名稱為D的對象,如果不存在,拋出異常.
模組B的__dict__列表可利用dir(B)來查看.
不存在模組B
如果不存在B這個鍵的話,則會為B建立一個模組對象,此時模組對象的__dict__列表為空白,然後在搜尋路徑下尋找並執行B.py,以填充模組B對象的__dict__列表,然後從__dict__列表中尋找名稱為D的對象,如果找不到,則拋出異常.
注:module ,模組的意思
根據上面修改代碼,查看sys.modules變化情況
#A.py#!/usr/bin/python# -*- coding: utf-8 -*-import systry: print ‘module B: %s‘%sys.modules[‘B‘]except Exception,e: print u‘沒有module B %s‘%etry: print ‘module A: %s‘%sys.modules[‘A‘]except Exception,e: print u‘沒有module A %s‘%efrom B import Dclass C(object): pass#B.pyfrom A import Cclass D(object): pass‘‘‘執行A.py結果:沒有module B ‘B‘沒有module A ‘A‘module B: <module ‘B‘ from ‘B.pyc‘>module A: <module ‘A‘ from ‘A.py‘>Traceback (most recent call last): File "A.py", line 4, in <module> from B import D File "B.py", line 4, in <module> from A import C File "A.py", line 4, in <module> from B import DImportError: cannot import name D
問題1答案
- 運行A.py,當執行到from B import D語句時,因為還沒有運行過B.py,所以sys.modules中沒有B這個鍵.會建立一個鍵B並賦值為模組B對象,只不過此時模組B對象是空的,裡面什麼都沒有;
- 然後,暫停執行A.py的其他語句,Python 在搜尋路徑下尋找B.py,找到同目錄下的B.py並運行,為了填充模組B對象中的__dict__列表.當執行到from A import C時,也會檢查sys.modules中是否有名為A的模組,但因為A.py還沒有讀取完,所以並沒有在sys.modules中緩衝對應的資訊.同樣,Python 會建立一個鍵A並賦值為空白的模組A對象.暫停執行B.py並尋找、從頭執行A.py.
- 這時,會再次執行到from B import D語句,由於在第一步時已經在sys.modules建立了鍵B的模組B對象,所以直接擷取到,但此時模組B對象中的__dict__列表還是空的,裡面什麼都沒有啊,所以找不到名為D的對象,拋出異常.
對照運行結果,是不是很符合- -!
(表述能力有限,多看代碼吧- -)
問題2 將上述from import 換成 import
#A1.py#!/usr/bin/python# -*- coding: utf-8 -*-import systry: print ‘module B1: %s‘%sys.modules[‘B1‘]except Exception,e: print u‘沒有module B1 %s‘%etry: print ‘module A1: %s‘%sys.modules[‘A1‘]except Exception,e: print u‘沒有module A1 %s‘%eimport B1class C(object): passtry: B1.D()except Exception,e: print u‘B中沒有屬性D‘,e#B1.pyimport A1class D(object): pass‘‘‘執行A.py結果:沒有module B1 ‘B1‘沒有module A1 ‘A1‘module B1: <module ‘B1‘ from ‘B1.pyc‘>module A1: <module ‘A1‘ from ‘A1.py‘>B中沒有屬性D ‘module‘ object has no attribute ‘D‘‘‘‘
由程式結果可知,將from…import…改成import後,程式不會出錯了,但是調用B1.D()時為什麼會拋出異常呢?
問題2答案
運行A1.py,當執行到import B1語句時,因為還沒有運行過B1.py,所以sys.modules中沒有B1這個鍵.會建立一個鍵B1並賦值為模組B1對象,只不過此時這個模組對象是空的,裡面什麼都沒有;
然後,暫停執行A1.py的其他語句,Python 在搜尋路徑下尋找B1.py,找到同目錄下的B1.py並運行,為了填充模組B1對象中的__dict__列表.當執行到import A1時,也會檢查sys.modules中是否有名為A1的模組,但因為A1.py還沒有讀取完,所以並沒有在sys.modules中緩衝對應的資訊.然後,同樣的,Python 會建立一個鍵A1並賦值為空白的模組A1對象.暫停執行B1.py並尋找、從頭執行A1.py.
這時,會再次執行到import B1語句,由於在第一步時已經在sys.modules建立了模組B1對象,模組B1對象已經存在了,不需要執行B1.py,所以繼續執行A1.py中的其他內容.
注意:此時模組B1仍為空白的,裡面什麼都沒有.
當執行到B1.D()時,由於在模組B1對象的__dict__列表找不到名為D的對象,拋出異常.
問題3 修改問題1中的程式使的能正確運行
#A2.pyfrom B2 import Dclass C(object): pass#B2.pyclass D(object): passfrom A2 import C
簡單說明:
A2.py->B2.py->A2.py時,D屬性已經在B2的__dict__列表中了,所以不會報錯…雖然這樣寫不會報錯,但是強烈不推薦這麼寫….
總結
當Python程式匯入其他模組時,要避免迴圈匯入,不然總會出意向不到的問題….
注:迴圈匯入,即A檔案匯入了B,B檔案又匯入了A.
重新匯入模組
如果更新了一個已經用import語句匯入的模組,內建函數reload()可以重新匯入並運行更新後的模組代碼.它需要一個模組對象做為參數.例如:
import foo
... some code ...
reload(foo) # 重新匯入 foo
在reload()運行之後的針對模組的操作都會使用新匯入代碼,不過reload()並不會更新使用舊模組建立的對象,因此有可能出現新舊版本對象共存的情況。*注意* 使用C或C++編譯的模組不能通過 reload() 函數來重新匯入。記住一個原則,除非是在調試和開發過程中,否則不要使用reload()函數
python之from 和import執行過程分析