對於含有 __init__.py 的目錄(如adir),其實它就是一個package,它的子目錄如果也包含 __init__.py,則只要將 adir 加入 sys.path,則它的字目錄就不用加了,python在import的時候會自動遍歷所有含有 __init__.py 的子目錄。
python文件的引入有2中方式:1、作為頂層執行腳本(執行入口)而加載;2、作為模塊被引入。如果你直接執行一個python文件,則它就被當作頂層執行腳本而被加載。如果你使用參數-m (python -m file.py),則該文件被當作模塊被引入, 如果該文件被其它文件以import的方式引入,則它也會被當成模塊。一個文件的引入方式只能是這兩種中的一種,而且某時刻只能是其中一種。
介紹了import,就必須介紹python的naming:
當文件被裝載之后,它就會在裝載器中獲得一個唯一的命名,變量叫做 __name__。如果文件作為頂層執行腳本被引入,則 __name__ == "__main__"。如果作為module被引入,則 __name__ 就是文件的文件名加上一些前綴,這些前綴就是packages/subpackages這樣的類似文件路徑的東西,不過是由點號dot隔開,而不是/隔開。注意其中的“類似”兩字,表明前綴和文件路徑不完全一樣。比如:
package/ __init__.py subpackage1/ __init__.py moduleX.py moduleA.py
如果你引入(即作為模塊被引入) moduleX,則它的 __name__ 就是 package.subpackage1.moduleX
,如果你引入moduleA
,則它的 __name__ 就是package.moduleA
。但是如果你直接執行moduleX,則它的 __name__就是 "__main__",如果你直接
執行
moduleA,它的名字就變成了
"__main__",模塊名
自動被舍棄。package.moduleA
作為模塊引入的時候,__name__ 屬性是隨引入的方式而不同的。一般有2種方式:被同級目錄里的其它文件引用,或經由package而被引用。以上面例子為例,如果被同級目錄里的文件引用,則moduleX
的 __name__ 屬性為 "moduleX
",而不是 "package.subpackage1.moduleX
"。因為python會將當前目錄自動加入search path,它並不知道自己所在的目錄是否屬於某packge。一個特例是,如果你使用的是交互式python命令行,則該命令行的session的 __name__ 屬性為
。"__main__"
因此,綜上所述,你引入一個module的方式(經由同級目錄里的其它文件引用,或經由package引用,也即 __name__ 屬性的值)是你能否將一個文件module成功引入的關鍵。
相對引入:
由於python為了保證package作為一個獨立的模塊,即將它拷貝到別處也不依賴於模塊外部的東西而能馬上運行,因此相對引入不允許引入package外的任何東西。
因此,相對引入有一下規則:
相對引入是使用module的 __name__ 屬性來判定它是否屬於一個package或在某package的位置。如果你使用相對引入如 from .. import foo
,則這里的 .. 是告訴python從當前目錄開始反向搜索本package去搜索 foo 模塊(向本package的頂層回溯兩個dot)。以上面的例子為例,如果當前模塊的 __name__ 是 package.subpackage1.moduleX
,則 ..moduleA
就意味着將找到 package.moduleA
。為了 ..
import 正確工作,模塊的 __name__ 必須擁有相應個數的dot,如 package.subpackage1.moduleX 模塊,向左數兩個dot,則是package模塊
。
如果你當前module的 __name__ 是
,則python會認為該module不在任何package中(即便它在),因為__name__中不包含dot,因此你無法在其文件中使用 .. import,也即無法使用 相對引入,否則你會得到"relative-import in non-package" 錯誤提示。"__main__"