1.要解決的問(wèn)題
Python在語(yǔ)義中存在著包奋献、模塊健霹、類(當(dāng)然還有函數(shù))這幾個(gè)概念。
在編寫Python代碼時(shí)瓶蚂,我們需要管理代碼的文件目錄結(jié)構(gòu)糖埋。
這時(shí)候會(huì)遇到這樣一種情況:
1.由于Python一個(gè)文件算一個(gè)模塊,一個(gè)帶__init__.py的目錄算一個(gè)包窃这。
2.而為了控制代碼文件不要過(guò)大瞳别,我們需要的是一個(gè)類(幾個(gè)類或加些許函數(shù))分配一個(gè)文件。
3.這時(shí)候會(huì)出現(xiàn)類似這樣的語(yǔ)句:
#第一種
importpackage_a.class_a_fileascaf
a=caf.ClassA()
#第二種
formpackage_a.class_a_file import *
a=ClassA()
#另外幾種就不意義列舉了...
以上除了直觀上可以看出import過(guò)長(zhǎng)外杭攻,隱藏的另一點(diǎn)是我們是希望一個(gè)類用一個(gè)文件祟敛,在使用多個(gè)相關(guān)類的時(shí)候就必須寫很多import。(注:我們可不想一堆代碼扎堆兆解,弄出一個(gè)超大代碼文件馆铁。)
2.解決方案要達(dá)到的效果
#文件目錄結(jié)構(gòu)
#|--demo.py
#|--package_a
#?? |--__init__.py
#?? |--class_a.py??#類ClassA
#?? |--class_b.py??#類ClassB和函數(shù)func_b()
#demo.py中可以直接使用
from package_a import *
a=ClassA()
b=ClassB()
func_b()
由于Python里一個(gè)帶__init__.py的目錄算一個(gè)包,所以利用這一機(jī)制锅睛,把類文件放在包里埠巨,用包來(lái)管理類。
注:在Python里“包是模塊现拒,而模塊不是包”辣垒。用system.modules可以取到的名字是包和模塊都有的,而用__package__卻能很好的區(qū)分包和模塊具练。也就是“包其實(shí)是一種特殊的模塊”乍构。
3.解決方案
這就是解決方案的文件base.py甜无,代碼很短:
import sys
_packet_={}
#它是個(gè)裝飾器扛点,item是類,或者函數(shù)
def export(item):
#獲取item的模塊對(duì)象
module=sys.modules[item.__module__]
#由模塊對(duì)象得到包對(duì)象
package=sys.modules[module.__package__]
#把item添加到包的__dict__里
package.__dict__[item.__name__]=item
#生成所有使用該解決方案的包的__all__變量岂丘,并把導(dǎo)出的item添加進(jìn)去
ifnotpackage.__name__in_packet_:
_packet_[package.__name__]=[]
_packet_[package.__name__].append(item.__name__)
#原封不動(dòng)地把item返回
returnitem
#它是個(gè)函數(shù)陵究,在包__init__.py里用于獲取__all__
def packet(name):
ifnotnamein_packet_:
_packet_[name]=[]
return_packet_[name]
代碼用意我寫在注釋里了,就是以裝飾器來(lái)把類添加到包的__dict__和__all__里奥帘。__all__需要利用packet在包里生成铜邮,不這么做只會(huì)使得from package_name import * 后不能找到類,需要寫具體的類名from package_name import ClassA寨蹋。
4.使用解決方案
先來(lái)看下使用解決方案后的目錄結(jié)構(gòu):
#文件目錄結(jié)構(gòu)(使用后結(jié)構(gòu)只多了base.py)
#|--base.py
#|--demo.py
#|--package_a
#?? |--__init__.py
#?? |--class_a.py??#類ClassA
#?? |--class_b.py??#類ClassB和函數(shù)func_b()
代碼處就需要做到以下幾點(diǎn):
1.關(guān)于被導(dǎo)出的類文件里應(yīng)該怎么做松蒜,這里以class_b.py為例子:
# ./package_a/class_b.py
#1.需要導(dǎo)入base
importbase
#2.使用export裝飾器,裝飾要導(dǎo)出的類或函數(shù)
@base.export
classClassB:pass
#2.同樣的export可以導(dǎo)出函數(shù)
@base.export
def func_b():
print('func_b')
2.使用了導(dǎo)出功能的包要做什么,這里以package_a包為例:
# ./package_a/__init__.py
#1.導(dǎo)入base
importbase
#2.導(dǎo)入將要導(dǎo)出的子模塊,需要具體模塊名字的形式已旧,from . import * 不可用
from.importclass_a,class_b
#3.用packet初始化__all__,這個(gè)可選秸苗,主要是看要不要支持 from 的用 * 導(dǎo)入
__all__=base.packet(__name__)
#4.這個(gè)是可選的,因?yàn)槿绻昧薩_all__會(huì)影響from *运褪【ィ可以用export把__init__.py里的項(xiàng)玖瘸,加入__all__
@base.export
def pafunc():
print('pafunc')
5.總結(jié)
使用該解決方案可以歸納為兩點(diǎn):
1.用@base.export標(biāo)記要導(dǎo)出的類或函數(shù)
2.在包__init__.py里初始化__all__ = base.packet(__name__)
3.(說(shuō)好的只有兩點(diǎn)呢?)其實(shí)第2點(diǎn)是可選的檀咙,不過(guò)最好加上雅倒。而在包的__init__.py里導(dǎo)入子模塊才是真正的第2點(diǎn)。不然子模塊不會(huì)被載入弧可,也談不上導(dǎo)出了蔑匣。
最后,demo.py里可以這么寫棕诵,和預(yù)期的效果一樣:)
# ./demo.py
from package_a import *
a=ClassA()# 上面的實(shí)例沒(méi)有給出殖演,不過(guò)假設(shè)有ClassA在class_a.py里的
b=ClassB()
func_b()學(xué)好python你需要一個(gè)良好的環(huán)境,一個(gè)優(yōu)質(zhì)的開(kāi)發(fā)交流群年鸳,群里都是那種相互幫助的人才是可以的趴久,我有建立一個(gè)python學(xué)習(xí)交流群,在群里我們相互幫助搔确,相互關(guān)心彼棍,相互分享內(nèi)容,這樣出問(wèn)題幫助你的人就比較多膳算,群號(hào)是304加上050最後799座硕,這樣就可以找到大神聚合的群,如果你只愿意別人幫助你涕蜂,不愿意分享或者幫助別人华匾,那就請(qǐng)不要加了,你把你會(huì)的告訴別人這是一種分享机隙。無(wú)論是學(xué)習(xí)任何一門語(yǔ)言蜘拉,基礎(chǔ)知識(shí),就是基礎(chǔ)功非常的重要有鹿,找一個(gè)有豐富編程經(jīng)驗(yàn)的老師或者師兄帶著你會(huì)少走很多彎路旭旭, 你的進(jìn)步速度也會(huì)快很多,無(wú)論我們學(xué)習(xí)的目的是什么葱跋,不得不說(shuō)Python真的是一門值得你付出時(shí)間去學(xué)習(xí)的優(yōu)秀編程
語(yǔ)言持寄。
感覺(jué)寫的好,對(duì)你有幫助娱俺,就點(diǎn)個(gè)贊唄稍味,別光只收藏哈.~( ̄▽ ̄)~