1. 標準 import
Python 中全部加載到內存的模塊都放在 sys.modules 。當 import 一個模塊時首先會在這個列表中查找是否已經加載了此模塊,若是加載了則只是將模塊的名字加入到正在調用 import 的模塊的 Local 名字空間中。若是沒有加載則從 sys.path 目錄中按照模塊名稱查找模塊文件,模塊能夠是py、pyc、pyd,找到後將模塊載入內存,並加到 sys.modules 中,並將名稱導入到當前的 Local 名字空間。
一個模塊不會重複載入。多個不一樣的模塊均可以用 import 引入同一個模塊到本身的 Local 名字空間,其實背後的 PyModuleObject 對象只有一個。說一個容易忽略的問題:
import 只能導入模塊,不能導入模塊中的對象(類、函數、變量等)。例如:模塊 A(A.py)中有個函數 getName,另外一個模塊不能經過 import A.getName 將 getName導入到本模塊,只能用 from A import getName。
2. 嵌套 import
1)順序嵌套
例如:本模塊導入 A 模塊(import A),A 中又 import B,B 模塊又能夠 import 其餘模塊……
這中嵌套比較容易理解,須要注意的一點就是各個模塊的 Local 名字空間是獨立的。對於上面的例子,本模塊 import A 以後本模塊只能訪問模塊 A,不能訪問模塊 B 及其餘模塊。雖然模塊 B 已經加載到內存了,若是訪問還要再明確的在本模塊中 import B。
2)循環嵌套
例如:文件[ A.py ]
from B import D
class C:pass
文件[ B.py ]
from A import C
class D:pass
爲何執行 A 的時候不能加載 D 呢?
若是將 A.py 改成:import B 就能夠了。
這是怎麼回事呢?
RobertChen:這跟Python內部 import 的機制是有關的,具體到 from B import D,Python 內部會分紅幾個步驟:
(1)在 sys.modules 中查找符號 「B」
(2)若是符號 B 存在,則得到符號 B 對應的 module 對象。
從 <modult B> 的 __dict__ 中得到符號 「D」 對應的對象,若是 「D」 不存在,則拋出異常。
(3)若是符號 B 不存在,則建立一個新的 module 對象 <module B>,注意,此時,module 對象的 __dict__ 爲空。
執行 B.py 中的表達式,填充 <module B> 的 __dict__。
從 <module B> 的 __dict__ 中得到 「D」 對應的對象,若是 「D」 不存在,則拋出異常。
因此這個例子的執行順序以下:
一、執行 A.py 中的 from B import D 因爲是執行的 python A.py,因此在 sys.modules 中並無 <module B> 存在, 首先爲 B.py 建立一個 module 對象 (<module B>) , 注意,這時建立的這個 module 對象是空的,裏邊啥也沒有, 在 Python 內部建立了這個 module 對象以後,就會解析執行 B.py,其目的是填充 <module B> 這個 __dict__。
二、執行 B.py中的from A import C 在執行B.py的過程當中,會碰到這一句, 首先檢查sys.modules這個module緩存中是否已經存在<module A>了, 因爲這時緩存尚未緩存<module A>, 因此相似的,Python內部會爲A.py建立一個module對象(<module A>), 而後,一樣地,執行A.py中的語句
三、再次執行A.py中的from B import D 這時,因爲在第1步時,建立的<module B>對象已經緩存在了sys.modules中, 因此直接就獲得了<module B>, 可是,注意,從整個過程來看,咱們知道,這時<module B>仍是一個空的對象,裏面啥也沒有, 因此從這個module中得到符號"D"的操做就會拋出異常。 若是這裏只是import B,因爲"B"這個符號在sys.modules中已經存在,因此是不會拋出異常的。
ZQ:圖解
啄木鳥社區《import 迷宮》:
http://wiki.woodpecker.org.cn/moin/MiscItems/2008-11-25
3. 包 import
只要一個文件夾下面有個 __init__.py 文件,那麼這個文件夾就能夠看作是一個包。包導入的過程和模塊的基本一致,只是導入包的時候會執行此包目錄下的 __init__.py 而不是模塊裏面的語句了。另外,若是隻是單純的導入包,而包的 __init__.py 中又沒有明確的其餘初始化操做,那麼此包下面的模塊是不會自動導入的。
例如:
有下面的包結構:
PA
|---- __init__.py
|---- wave.py
|---- PB1
|---- __init__.py
|---- pb1_m.py
|---- PB2
|---- __init__.py
|---- pb2_m.py
有以下程序:
import sys
import PA.wave
#1
import PA.PB1
#2
import PA.PB1.pb1_m as m1
#3
import PA.PB2.pb2_m
#4
PA.wave.getName()
#5
m1.getName()
#6
PA.PB.pb2_m.getName()
#7
1) 當執行 #1 後,sys.modules 會同時存在 PA、PA.wave 兩個模塊,此時能夠調用 PA.wave 的任何類或函數了。但不能調用 PA.PB1(2) 下的任何模塊。當前 Local 中有了 PA 名字。
2) 當執行 #2 後,只是將 PA.PB1 載入內存,sys.modules 中會有 PA、 PA.wave、PA.PB1 三個模塊,可是 PA.PB1 下的任何模塊都沒有自動載入內存,此時若是直接執行 PA.PB1.pb1_m.getName() 則會出錯,由於 PA.PB1 中並無 pb1_m 。當前 Local 中仍是隻有 PA 名字,並無 PA.PB1 名 字。
3) 當執行 #3 後,會將 PA.PB1 下的 pb1_m 載入內存,sys.modules 中會有 PA、PA.wave、PA.PB一、PA.PB1.pb1_m 四個模塊,此時能夠執行 PA.PB1.pb1_m.getName() 了。因爲使用了 as,當前 Local中除了 PA 名字,另外添加了 m1 做爲 PA.PB1.pb1_m 的別名。
4) 當執行 #4 後,會將 PA.PB二、PA.PB2.pb2_m 載入內存,sys.modules 中會有 PA、PA.wave、PA.PB一、PA.PB1.pb1_m、PA.PB二、PA.PB2.pb2_m 六個模塊。當前 Local 中仍是隻有 PA、m1。
下面的 #5,#6,#7 都是能夠正確運行的。
注意的是:若是 PA.PB2.pb2_m 想導入 PA.PB1.pb1_m、PA.wave 是能夠直接成功的。最好是採用明確的導入路徑,對於 ./.. 相對導入路徑仍是不推薦用。
原文:
http://blog.csdn.net/zbyufei/article/details/5894645
======================================
from module import *把module中的成員所有導到了當前的global namespace,訪問起來就比較方便了。固然,python style通常不建議這麼作,由於可能引發name conflict。html
但還有另一個問題 - 你覺得你修改了某個變量,其實,被from module import *後的那個並無被更新,很是危險,由於程序有可能還能夠正常運行, 只不過結果錯了,到了production才被發現就比較慘了。python
舉個例子:緩存
你定義了一些變量在base模塊中:函數
# reference data type
class Demo:
def __init__(self, name):
self.name = name
demo = Demo('Demo')
# primitive type
foo = 1
而後在一個模塊中用from module import 的方式讀它:post
from base import *
def read():
print 'reference data id: ' + str(id(demo))
print 'reference data value : ' + demo.name
print 'primitive data id: ' + str(id(foo))
print 'primitive data value: ' + str(foo)
在另一個模塊中寫它:ui
import base
def write():
print "\nOriginal:"
print "Original reference data id: " + str(id(base.demo))
base.demo.name = "Updated Demo" # this will reflect that change
#base.demo = base.Demo("Updated Demo") # this won't relfect the change
print "Original data id: " + str(id(base.foo))
base.foo = 1000
print "Original data id after assignment: " + str(id(base.foo))
而後先寫,後讀,看寫的內容是否有效:this
import read
import write
print "before write"
read.read()
write.write()
print "\nafter write"
read.read()
結論是沒有,緣由是:url
- 當你用from module import時,實際上是copy了一份reference或者pointer,指向一分內存,var和module.var都指向同一分內存
- 當你修改module.var時,其實你是讓它指向了另一分內存,此時var和module.var指向的是不一樣的內存
- 因此,雖然module.var的值變了,var仍是指向原來那分內存,原來的值
這個對於object,比較容易理解,你能夠直接修改object裏的值,這個是有效的,可是當你指向另一個object時就無效了。 對於primitive類型來說,其實也是一個道理,由於每次賦值,都是讓其指向一個不一樣的內存地址,而不是inplace修改已有的那分內存 - 這個很容易驗證:spa
In [1]: a = 10
In [2]: id(a)
Out[2]: 20429204
In [3]: a = 100
In [4]: id(a)
Out[4]: 20430108
因此,建議是除非是一個quick and dirty的腳本,不然不要使用from module import *!.net