前言
在python的模組有兩種組織方式,一種是單純的python文件,文件名就是模組名,一種是包,包是一個包含了若干python文件的目錄,目錄下必須有一個文件__init__.py,這樣目錄名字就是模組名,包裡的python檔案也可以透過包名.檔名的方式import
import語法
import語法有兩種
1、直接import模組
rrrereee 2、從模組import物件(下級模組,類,函數,變數等)import Module import Module as xxas語法是用來設定物件(這裡用物件泛指模組,類,函數等等)別名,import將物件名字引入了當前文件的名字空間假設有如下目錄結構
from Module import Name from Module immport Name as yy在當前目錄下,以下語句都是有效的
├── A.py └── pkg ├── B.py └── __init__.py為了簡化討論,下面將不會對as
import A import pkg import pkg.B from pkg import B
為了簡化討論,下面將不會對as
import步驟
如果是from A import B,先為A創建module對象,再解析A,從中尋找B並填充到A的__dict__中
嵌套import
#filename: A.py from B import BB class AA:pass #filename: B.py from A import AA class BB:pass這時不管是執行A.py還是B.py都會拋出ImportError的異常,假設我們執行的是A.py,究其原因如下文件A.py執行from B import BB,會先掃描B.py,同時在A的名字空間中為B創建module對象,試圖從B中查找BB掃描B.py第一行執行from A import AA ,此時又會去掃描A.py
掃描A.py第一行執行from B import BB,由於步驟1已經為B創建module對象,所以會直接從B的module對象的__dict__中獲取BB ,此時顯然BB是取得不到的,於是拋出異常
將A.py或B.py中的兩行程式碼交換位置
包的import
pkg ├── __init__.py └── file.py其中__init__.py內容內容如下
argument = 0 class A:pass在和pkg同級目錄下執行如下語句都是OK的
>>> import pkg >>> import pkg.file >>> from pkg import file >>> from pkg import A >>> from pkg import argument但如下語句是錯誤的
>>> import pkg.A >>> import pkg.argument報錯詞,A和B都必須是模組(檔案或套件)
相對導入和絕對導入
app ├── __inti__.py ├── mod1 │ ├── file1.py │ └── __init__.py ├── mod2 │ ├── file2.py │ └── __init__.py └── start.py
其中app/start.py內容為import mod1.file1
再來看原因,我們先具體來看原因一下導入模組時的一些規則
在沒有明確指定包結構的情況下,python是根據__name__來決定一個模組在包中的結構的,如果是__main__則它本身是頂層模組,沒有包結構,如果是A.B.C結構,那麼頂層模組是A。
基本上遵循這樣的原則
如果是絕對導入,一個模組只能導入自身的子模組或和它的頂層模組同級別的模組及其子模組
如果是相對導入,一個模組必須有包結構且只能導入它的頂層模組內部的模組
有目錄結構如下
A ├── B1 │ ├── C1 │ │ └── file.py │ └── C2 └── B2
其中A,B1,B2,C1,C2都为包,这里为了展示简单没有列出__init__.py文件,当file.py的包结构为A.B1.C1.file(注意,是根据__name__来的,而不是磁盘的目录结构,在不同目录下执行file.py时对应的包目录结构都是不一样的)时,在file.py中可采用如下的绝对的导入
import A.B1.C2 import A.B2
和如下的相对导入
from .. import C2 from ... import B2
什么情况下会让file.py的包结构为A.B1.C1.file呢,有如下两种
在A的上层目录执行python -m A.B1.C1.file, 此时明确指定了包结构
在A的上层目录建立文件start.py,在start.py里有import A.B1.C1.file,然后执行python start.py,此时包结构是根据file.py的__name__变量来的
再看前面出错的两种情况,第一种执行python file1.py和python mod1/file1.py,此时file.py的__name__为__main__ ,也就是说它本身就是顶层模块,并没有包结构,所以会报错
第二种情况,在执行python -m mod1.file1和python start.py时,前者明确告诉解释器mod1是顶层模块,后者需要导入file1,而file1.py的__name__为mod1.file1,顶层模块为也mod1,所以在file1.py中执行from ..mod2 import file2时会报错 ,因为mod2并不在顶层模块mod1内部。通过错误堆栈可以看出,并不是在start.py中绝对导入时报错,而是在file1.py中相对导入报的错
那么如何才能偶正确执行呢,有两种方法,一种是在app上层目录执行python -m app.mod1.file1,另一种是改变目录结构,将所有包放在一个大包中,如下
app ├── pkg │ ├── __init__.py │ ├── mod1 │ │ ├── __init__.py │ │ └── file1.py │ └── mod2 │ ├── __init__.py │ └── file2.py └── start.py
start.py内容改成import pkg.mod1.file1,然后在app下执行python start.py
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家学习或者使用python能带来一定的帮助,如有疑问大家可以留言交流。
更多python中import学习备忘笔记相关文章请关注PHP中文网!