中文字幕理论片,69视频免费在线观看,亚洲成人app,国产1级毛片,刘涛最大尺度戏视频,欧美亚洲美女视频,2021韩国美女仙女屋vip视频

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開(kāi)通VIP
深入理解Python中import機(jī)制

大型項(xiàng)目中為了維護(hù)方便,通常使用模塊化開(kāi)發(fā),模塊化的過(guò)程中,就會(huì)涉及到各種包或者模塊的相互導(dǎo)入,即使是對(duì)于有多個(gè)項(xiàng)目的Python開(kāi)發(fā)者來(lái)說(shuō), import 也會(huì)讓人困惑!本文帶你深入了解python中 import 的內(nèi)在機(jī)制,從而避免import導(dǎo)入引發(fā)的異常。

概念

模塊(module)

任何 .py 文件都可以稱為模塊

包(package)

可以將多個(gè)模塊放入一個(gè)包中,就像電腦中的文件夾,但與文件夾的區(qū)別是,package包含 __init__.py 文件

Python import 的搜索路徑

當(dāng)我們執(zhí)行 python xx.py 時(shí),python是如何幫我們正確定位包所在的目錄呢?其實(shí)系統(tǒng)是按照以下順序來(lái)尋找的:

1.系統(tǒng)內(nèi)置模塊,比如os, sys模塊2.入口文件所在的目錄,比如main.py所在的目錄3.Python環(huán)境變量,也就是我們平時(shí)pip install后的包所在的目錄,如Anaconda下的site-packages目錄

在Python中,如果遇到了import錯(cuò)誤,我們可以通過(guò)以下命令查看搜索路徑:

import sysprint(sys.path)

結(jié)果:

sys.path: ['/Users/root/Python/project','/Users/root/anaconda3/lib/python36.zip','/Users/root/anaconda3/lib/python3.6','/Users/root/anaconda3/lib/python3.6/lib-dynload','/Users/root/.local/lib/python3.6/site-packages','/Users/root/anaconda3/lib/python3.6/site-packages','/Users/root/anaconda3/lib/python3.6/site-packages/Sphinx-1.5.6-py3.6.egg','/Users/root/anaconda3/lib/python3.6/site-packages/aeosa','/Users/root/anaconda3/lib/python3.6/site-packages/mdr-0.0.1-py3.6-macosx-10.7-x86_64.egg']

可以看到,其中第一個(gè)目錄是我們運(yùn)行的文件所在目錄,其它都是Python環(huán)境變量中的目錄

執(zhí)行 python xx.py 發(fā)生了什么?

直接被Python解釋器運(yùn)行的文件,稱之為程序的 入口文件 ,在Python中,入口文件有且僅有一個(gè)

我們經(jīng)常使用以下語(yǔ)句:

# in main.pyif __name__=='__main__': run()

__name__=='__main__' 這個(gè)語(yǔ)句就是檢測(cè)當(dāng)前腳本是否被當(dāng)作入口文件使用,如果被當(dāng)做入口文件使用,那么就運(yùn)行 if __name__=='__main__': 下面的代碼塊,如果只是當(dāng)做模塊被其他的模塊 import 進(jìn)去使用,那就不應(yīng)該運(yùn)行這部分代碼塊。

因此,判斷一個(gè)文件是否被python解釋器當(dāng)做入口文件對(duì)待,是可以打印腳本的 __name__ 變量的。

# in main.pyprint(__main__)

入口文件和 import 路徑有什么關(guān)系呢?

如果我們把 xx.py 當(dāng)做入口文件,那么Python解釋器,就會(huì)將 xx.py 所在的目錄,加入到sys.path中,作為import時(shí)搜索的根目錄。簡(jiǎn)言之,你用 python filename.py 執(zhí)行哪個(gè)文件,Python解釋器就會(huì)將哪個(gè)文件所在目錄加入 import 的搜索目錄。

新問(wèn)題:在模塊化的項(xiàng)目中,如何讓Python解釋器搜索到所有的模塊呢?

這引入了一個(gè)項(xiàng)目結(jié)構(gòu)合理性的問(wèn)題: 入口文件的目錄層級(jí)應(yīng)該是頂層的 ,也就是入口文件目錄層級(jí)不應(yīng)該低于任何模塊或者包,一個(gè)常見(jiàn)的目錄結(jié)構(gòu)通常如下:

$ tree./project├── package│ ├── __init__.py│ ├── sub_pkg1│ │ ├── __init__.py│ │ ├── module_X.py│ │ └── module_Y.py│ └── sub_pkg2│ ├── __init__.py│ └── module_Z.py└── main.py(入口文件)

如果我們執(zhí)行 python main.py ,那么main.py就會(huì)被當(dāng)做入口文件,所在目錄 project 就會(huì)被加入import的搜索路徑,那么我們將能夠搜索 package1 和 package2 中的模塊;現(xiàn)在假設(shè)我們直接運(yùn)行 python module_X.py ,此時(shí)入口文件變成了 module_X.py ,那么我們 import 搜索的根目錄為 sub_pkg1 ,當(dāng)我們?cè)噲D去 import sub_pkg2 中的文件時(shí),就會(huì)引發(fā)異常。

上述問(wèn)題引入了一個(gè)準(zhǔn)則:除了入口文件之外,其他文件都不應(yīng)該通過(guò)python xx.py來(lái)運(yùn)行,那如果我們想運(yùn)行某個(gè)模塊怎么辦?

答案是:通過(guò) python -m sub_pkg1.module_X 來(lái)運(yùn)行!

python -m 的意思是將module當(dāng)做模塊來(lái)運(yùn)行,同時(shí) sub_pkg1.module_X 是導(dǎo)入路徑,這樣子就不會(huì)找不到模塊了。

上述解決方案引入一個(gè)比較好的實(shí)踐:

如果在一個(gè)大型項(xiàng)目中,你經(jīng)常使用 cd 命令跳轉(zhuǎn)到各種不同層級(jí)的目錄中 Python xx.py 運(yùn)行某個(gè)模塊,那你可能得嘗試使用 Python -m 了,也就是我們最好在項(xiàng)目的根目錄下完成所有的模塊的測(cè)試。當(dāng)然,完善的項(xiàng)目,應(yīng)該有專門的測(cè)試目錄如 tests , 這個(gè)以后有機(jī)會(huì)再講。

Python中的相對(duì)導(dǎo)入和絕對(duì)導(dǎo)入

在Python中,存在相對(duì)導(dǎo)入和絕對(duì)導(dǎo)入兩種import機(jī)制,但無(wú)論是絕對(duì)導(dǎo)入還是相對(duì)導(dǎo)入,都需要一個(gè)參照物,不然「絕對(duì)」與「相對(duì)」的概念就無(wú)從談起。絕對(duì)導(dǎo)入的參照物是項(xiàng)目的根文件夾,相對(duì)導(dǎo)入?yún)⒄瘴锸钱?dāng)前模塊,當(dāng)我們使用相對(duì)導(dǎo)入時(shí),需要給出相對(duì)于當(dāng)前模塊,想導(dǎo)入模塊所在的位置。

# 相對(duì)導(dǎo)入from . import foolfrom .package import foolfrom ..module import spam# 絕對(duì)導(dǎo)入,項(xiàng)目根目錄是appfrom app.package import fool

相對(duì)導(dǎo)入可以避免硬編碼帶來(lái)的維護(hù)問(wèn)題,例如我們改了某一頂層包的名字,那么其子包所有的導(dǎo)入就都不能用了。除非我們手動(dòng)修改頂層包名。 但是存在相對(duì)導(dǎo)入語(yǔ)句的模塊,不能直接使用 python xx.py 的方式運(yùn)行,否則會(huì)有異常:

ValueError: Attempted relative import in non-package

·如果是絕對(duì)導(dǎo)入,一個(gè)模塊只能導(dǎo)入自身的子模塊或和它的頂層模塊同級(jí)別的模塊及其子模塊·如果是相對(duì)導(dǎo)入,一個(gè)模塊必須有 包結(jié)構(gòu) (意味著有 __init__.py )且只能導(dǎo)入它的頂層模塊內(nèi)部的模塊 所以,如果一個(gè)模塊被直接運(yùn)行,Python會(huì)將該模塊當(dāng)做 頂層模塊(top level) ,不再當(dāng)做一個(gè)包來(lái)對(duì)待,因此不存在層次結(jié)構(gòu),所以找不到其他的相對(duì)路徑,所以如果直接運(yùn)行python xx.py ,而xx.py有相對(duì)導(dǎo)入就會(huì)報(bào)錯(cuò)

看下面例子:

$ tree./project├── package│   ├── __init__.py│   ├── sub_pkg1│   │   ├── __init__.py│     │     ├── module_X.py│   │   └── module_Y.py│   └── sub_pkg2│       ├── __init__.py│       └── module_Z.py└── main.py(入口文件)

module_X.py

from . import module_Yprint 'X __name__', __name__

module_Y.py

print  'Y __name__', __name__

當(dāng)我們直接運(yùn)行 python sub_pkg1/module_X.py 的時(shí)候,會(huì)報(bào)錯(cuò)

ValueError: Attempted relative import in non-package

當(dāng)我們這樣運(yùn)行的時(shí)候 python -m sub_pkg1.module_X , 才能正常運(yùn)行

Y __name__ sub_pkg1.moduleYX __name__ __main__

為什么會(huì)這樣?簡(jiǎn)單地說(shuō),直接運(yùn)行 .py 文件和 import 這個(gè)文件有很大區(qū)別。Python 解釋器判斷一個(gè) py 文件屬于哪個(gè) package 時(shí)并不完全由該文件所在的文件夾決定。它還取決于這個(gè)文件是如何 load 進(jìn)來(lái)的( 直接運(yùn)行 or import )。

有兩種方式加載一個(gè) py 文件:

·作為 top-level 腳本 作為 top-level 腳本指的是直接運(yùn)行腳本,比如 python xx.py。有且只能有一個(gè) top-level 腳本,就是最開(kāi)始執(zhí)行的那個(gè)(比如 python xx.py 中的 xx.py)?!ぷ鳛?module 作為 module 是指,執(zhí)行 python -m xx,或者在其它 py 文件中用 import 語(yǔ)句來(lái)加載,那么它就會(huì)被當(dāng)作一個(gè) module。

當(dāng)一個(gè) py 文件被加載之后,它會(huì)被賦予一個(gè)名字,保存在 __name__ 屬性中。如果是 top-level 腳本,那么名字就是 __main__ 。如果是作為 module,名字就是把它所在的 packages/subpackages 和文件名用 . 連接起來(lái)。

例如,moduleX 被 import 進(jìn)來(lái),它的名字就是
package.subpackage1.moduleX。如果 import 了 moduleA,它的名字是 package.moduleA。如果直接運(yùn)行 moduleX 或 moduleA,那么名字就都是 __main__ 了。

所以上面的 module_X 的 __name__ 是 __main__ , 因?yàn)樗侵苯舆\(yùn)行的, module_Y 的 __name__ 是 sub_pkg1.module_Y ,因?yàn)樗潜籭mport 來(lái)使用的。

常見(jiàn)幾種import需求

module_X.py

# module_X導(dǎo)入module_Y# 相對(duì)導(dǎo)入from . import module_Y# 絕對(duì)導(dǎo)入from package.sub_pkg1 import module_Y

module_X.py

# module_X導(dǎo)入module_Z# 相對(duì)導(dǎo)入from ..sub_pkg2 import module_Z# 絕對(duì)導(dǎo)入from package.sub_pkg2 import module_Z

main.py

# main.py導(dǎo)入module_Yfrom package.sub_pkg1 import module_Y

特別需要注意的是,雖然上述模塊導(dǎo)入路徑是對(duì)的,除了 main.py 之外,都不可以通過(guò) python xx.py 的方式運(yùn)行,而是通過(guò)前面討論過(guò)個(gè) python -m 方式運(yùn)行。

相對(duì)導(dǎo)入和絕對(duì)導(dǎo)入的優(yōu)缺點(diǎn)

相對(duì)導(dǎo)入可以避免硬編碼,對(duì)于包的維護(hù)是友好的。其缺點(diǎn)是可讀性較差,讓人很難清楚地了解到資源所在的位置。

絕對(duì)路徑導(dǎo)入由于其直觀往往是大家的首選。只要看一下導(dǎo)入語(yǔ)句你就能知道資源是從什么位置導(dǎo)入的。再者,就算當(dāng)前import語(yǔ)句的位置發(fā)生了變化,此絕對(duì)路徑導(dǎo)入的資源依然有效。實(shí)際上,官方也推薦使用絕對(duì)路徑導(dǎo)入。

《Python之禪》中提到:

明確 由于 隱晦

縱觀一些優(yōu)秀的開(kāi)源項(xiàng)目,絕對(duì)導(dǎo)入的使用也是更為普遍的。我個(gè)人通常以絕對(duì)導(dǎo)入為主,相對(duì)導(dǎo)入為輔,只會(huì)在同一個(gè)模塊層級(jí)中使用一些相對(duì)導(dǎo)入,如: from .fool import spam ,很少會(huì)使用 from ...fool import spam 這樣讓人迷惑的相對(duì)導(dǎo)入。

解決import錯(cuò)誤的調(diào)試思路

1.區(qū)分是文件夾還是包(有無(wú) __init__.py )?

2.非入口文件是否是使用python -m運(yùn)行的?

3.入口文件的層級(jí),是否高于任何包或者模塊?

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Python中模塊,包,庫(kù),框架都是啥?
編寫 python package 中的 setup.py 文件
Python模塊包中__init__.py文件的作用
UC頭條:[Python基礎(chǔ)]Python包(庫(kù))
python中如何正確使用import
python3
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服