python中_init_.py的作用
最近有幾個(gè)小伙伴問了我一個(gè)經(jīng)典問題:“__init__.py 到底有啥用?”
其實(shí)這個(gè)問題挺常見的,尤其是對(duì)Python新手來說簡直就是一團(tuán)迷霧。今天就站在一位老程序員的角度來給大家嘮一嘮__init__.py的用途和奧秘,順便幫大家“踩踩坑”,看看有哪些用法需要注意。
1. __init__.py 是個(gè)啥?
__init__.py,顧名思義,這個(gè)文件名就透露出它是用來“初始化”的。在Python里,它主要用于標(biāo)識(shí)一個(gè)目錄是一個(gè)“包(Package)”。
你在項(xiàng)目里新建了一個(gè)文件夾,要讓它成為一個(gè)可供導(dǎo)入的模塊包,最簡單的辦法就是在里面加一個(gè)__init__.py。
比如,咱們有個(gè)項(xiàng)目結(jié)構(gòu)如下:
當(dāng)我們想要在外部使用my_project這個(gè)包時(shí),就可以這樣導(dǎo)入:
有了__init__.py的存在,Python才知道m(xù)y_project是一個(gè)包,而不是一個(gè)普通的文件夾。
所以這個(gè)文件的基本作用就是:告訴Python,“這里是個(gè)包,你可以在其他地方導(dǎo)入我!”
2. __init__.py 還能做些啥?
很多初學(xué)者以為這個(gè)文件只能“聲明”包,實(shí)際上它的用法比你想象的要豐富得多。在__init__.py里你可以編寫代碼,它會(huì)在包被導(dǎo)入時(shí)自動(dòng)執(zhí)行。這有什么用呢?我給大家舉幾個(gè)常見的例子:
模塊初始化操作
假如你有一個(gè)需要初始化配置的工具包,你可以在__init__.py里直接搞定這些初始化工作。
這樣,當(dāng)你一導(dǎo)入my_project時(shí),config.yaml就被自動(dòng)加載了,是不是很方便?你再也不用在每個(gè)子模塊里重復(fù)配置路徑啦!
控制子模塊導(dǎo)入
通過在__init__.py中用from .sub_module import some_function的方式,可以直接在import package_name的時(shí)候就將所有常用的子模塊或者函數(shù)導(dǎo)入,這樣你就能從包的頂級(jí)目錄直接訪問子模塊的內(nèi)容了:
你看,這種做法就好比你開了一個(gè)餐廳,顧客剛一進(jìn)門就能看到招牌菜,這樣體驗(yàn)就好了,少了很多繞路時(shí)間。
包級(jí)別變量和函數(shù)的初始化
你還可以在__init__.py里設(shè)置一些全局變量,或者定義一些包級(jí)別的工具函數(shù)。
這樣在任何地方,只要你導(dǎo)入了my_project,就能直接調(diào)用show_info()了。
3. __init__.py 的一些“坑”
俗話說得好,“有光的地方就有陰影”。別看__init__.py這么實(shí)用,里面也有不少坑,尤其是**循環(huán)導(dǎo)入(Circular Import)**的問題,這個(gè)坑可是踩一次懷疑人生那種級(jí)別的。
什么是循環(huán)導(dǎo)入?
假設(shè)你有兩個(gè)模塊module1和module2,然后你在module1.py中寫了這樣一段代碼:
然后你又在module2.py里這樣寫:
這就會(huì)導(dǎo)致Python在導(dǎo)入包的時(shí)候出現(xiàn)死循環(huán),結(jié)果是兩邊互相等待對(duì)方加載,最終就會(huì)報(bào)錯(cuò)或者無法正常導(dǎo)入。
如何解決?
一般來說,解決方案有兩種:
延遲導(dǎo)入:將導(dǎo)入語句放在函數(shù)內(nèi)部,而不是放在文件頭部。
重構(gòu)代碼結(jié)構(gòu):把相互依賴的部分提取出來,放到一個(gè)公共模塊里,這樣兩個(gè)模塊就不會(huì)直接互相依賴了。
4. __init__.py 和相對(duì)導(dǎo)入的關(guān)系
另外,再講一個(gè)可能讓人頭疼的點(diǎn)——相對(duì)導(dǎo)入和絕對(duì)導(dǎo)入。很多小伙伴可能會(huì)在__init__.py里用相對(duì)導(dǎo)入的語法,比如:
乍看上去沒啥問題,但等到你跑module1.py這個(gè)文件時(shí),就會(huì)發(fā)現(xiàn)——Boom!報(bào)錯(cuò)了!因?yàn)橄鄬?duì)導(dǎo)入的方式要求你必須從頂層包開始導(dǎo)入。而你直接執(zhí)行module1.py,Python根本不知道它是從哪個(gè)包里來的。
解決方案呢?我建議——盡量使用絕對(duì)導(dǎo)入,比如這樣:
這樣不管你是直接運(yùn)行module1.py,還是導(dǎo)入整個(gè)my_project,都不會(huì)有問題。
5. 還有哪些小技巧?
說了這么多,最后再給大家提幾個(gè)小技巧,幫你在使用__init__.py時(shí)少走彎路:
避免復(fù)雜邏輯:不要在__init__.py中寫太復(fù)雜的業(yè)務(wù)邏輯。它的職責(zé)應(yīng)該是輕量級(jí)的初始化和導(dǎo)入,不然以后維護(hù)起來會(huì)非常麻煩。
模塊導(dǎo)出控制:你可以用__all__來控制從包中導(dǎo)出哪些模塊或變量。
這樣當(dāng)你用from my_project import *時(shí),Python只會(huì)導(dǎo)入__all__指定的內(nèi)容。
合并子模塊:你可以在__init__.py中把子模塊的功能合并到一個(gè)命名空間中,讓用戶使用起來更方便。
記錄導(dǎo)入順序:如果你的包里有很多子模塊,建議記錄導(dǎo)入順序,避免因?yàn)閷?dǎo)入順序?qū)е乱恍┰幃惖腂ug。
總體來說,__init__.py用得好,它能讓整個(gè)包管理得井井有條,用得不好,它就會(huì)變成你代碼里的“絆腳石”。
到此這篇關(guān)于python中_init_.py的作用的文章就介紹到這了,更多相關(guān)python _init_.py內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python中的異常處理try/except/finally/raise用法分析
這篇文章主要介紹了Python中的異常處理try/except/finally/raise用法,結(jié)合實(shí)例形式分析了Python異常處理try/except/finally/raise相關(guān)功能與使用操作技巧,并附帶了Python常見異常的表格說明,需要的朋友可以參考下2019-02-02解決每次打開pycharm直接進(jìn)入項(xiàng)目的問題
今天小編就為大家分享一篇解決每次打開pycharm直接進(jìn)入項(xiàng)目的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-10-10numpy創(chuàng)建單位矩陣和對(duì)角矩陣的實(shí)例
今天小編就為大家分享一篇numpy創(chuàng)建單位矩陣和對(duì)角矩陣的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-11-11使用Python爬了4400條淘寶商品數(shù)據(jù),竟發(fā)現(xiàn)了這些“潛規(guī)則”
這篇文章主要介紹了使用Python爬了4400條淘寶商品數(shù)據(jù),竟發(fā)現(xiàn)了這些“潛規(guī)則”,筆者用 Python 爬取淘寶某商品的全過程,并對(duì)商品數(shù)據(jù)進(jìn)行了挖掘與分析,最終得出結(jié)論。需要的朋友可以參考下2018-03-03python使用Tkinter顯示網(wǎng)絡(luò)圖片的方法
這篇文章主要介紹了python使用Tkinter顯示網(wǎng)絡(luò)圖片的方法,涉及Python操作圖片的相關(guān)技巧,需要的朋友可以參考下2015-04-04四種Python機(jī)器學(xué)習(xí)超參數(shù)搜索方法總結(jié)
在建模時(shí)模型的超參數(shù)對(duì)精度有一定的影響,而設(shè)置和調(diào)整超參數(shù)的取值,往往稱為調(diào)參。本文將演示在sklearn中支持的四種基礎(chǔ)超參數(shù)搜索方法,需要的可以參考一下2022-11-11