0、說(shuō)到底洽损,Python 的模塊是什么革半?
答:模塊就是程序碑定。沒(méi)錯(cuò)又官,所謂模塊就是平時(shí)我們寫的任何代碼,然后保存的每一個(gè) “.py” 結(jié)尾的文件碘赖,都是一個(gè)獨(dú)立的模塊外构。
1普泡、我們現(xiàn)在有一個(gè) hello.py 的文件审编,里邊有一個(gè) hi() 函數(shù):
def hi():
print('Hi everyone, i love FishC.com!')
請(qǐng)問(wèn)我如何在另一個(gè)源文件 test.py 里邊使用 hello.py 的 hi() 函數(shù)呢?
答:只需要在 test.py 中導(dǎo)入 hello 模塊(文件名 = 模塊名)即可使用 hello.py 中的 hi() 函數(shù)砰嘁。
2、你知道的總共有幾種導(dǎo)入模塊的方法矮湘?
答:我們總共介紹了三種導(dǎo)入模塊的方法:
- 第一種:import 模塊名
- 第二種:from 模塊名 import 函數(shù)名
- 第三種:import 模塊名 as 新名字
3、曾經(jīng)我們講過(guò)有辦法阻止 from...import * 導(dǎo)入你的“隱私”屬性板祝,你還記得是怎么做到的嗎?
答:如果你不想模塊中的某個(gè)屬性被 from...import * 導(dǎo)入孤里,那么你可以給你不想導(dǎo)入的屬性名稱前邊加上一個(gè)下劃線( _ )橘洞。不過(guò)需要注意的是,如果使用 import ... 導(dǎo)入整個(gè)模塊炸枣,或者顯示的使用 import xx._oo 導(dǎo)入某個(gè)屬性,那么這個(gè)隱藏方法就不起作用了适肠。
4、倘若有 a.py 和 b.py 兩個(gè)文件敦跌,內(nèi)容如下:
# a.py
def sayHi():
print("嗨逛揩!我是A模塊!")
# b.py
def sayHi():
print("嗨!我是B模塊辩稽!")
那么我在 test.py 文件中執(zhí)行以下操作,會(huì)打印什么結(jié)果逞泄?
# test.py
from a import sayHi
from b import sayHi
sayHi()
答:會(huì)打印“嗨!我是B模塊各谚!”侮腹,因?yàn)榈诙螌?dǎo)入的 b 模塊把 a 模塊的同名函數(shù) sayHi() 給覆蓋了稻励,這就是所謂命名空間的沖突父阻。所以,在項(xiàng)目中履婉,特別是大型項(xiàng)目中,我們應(yīng)該避免使用 from...import... 仇冯,除非你非常明確不會(huì)造成命名沖突已烤。
5妓羊、執(zhí)行下邊 a.py 和 b.py 任何一個(gè)文件,都會(huì)報(bào)錯(cuò)躁绸,請(qǐng)嘗試解釋一下此現(xiàn)象。
# a.py
from b import y
def x():
print('x')
# b.py
from a import x
def y():
print('y')
答:這是個(gè)循環(huán)嵌套導(dǎo)入問(wèn)題剥哑。無(wú)論運(yùn)行 a.py 和 b.py 哪一個(gè)文件都會(huì)拋出 ImportError 異常淹父。這是因?yàn)樵趫?zhí)行其中某一個(gè)文件(a.py)的加載過(guò)程中,會(huì)創(chuàng)建模塊對(duì)象并執(zhí)行對(duì)應(yīng)的字節(jié)碼弹灭。但當(dāng)執(zhí)行第一個(gè)語(yǔ)句的時(shí)候需要導(dǎo)入另一個(gè)文件( from b import y ),因此CPU 會(huì)轉(zhuǎn)而去加載另一個(gè)文件(b.py)。同理逻翁,執(zhí)行另一個(gè)文件的第一個(gè)語(yǔ)句( from a import x )恰好也是需要導(dǎo)入之前的的文件(a.py)。此時(shí)八回,之前的文件處于僅導(dǎo)入第一條語(yǔ)句的階段驾诈,因此其對(duì)應(yīng)的字典中并不存在 x , 故拋出 “ImportError: cannot import name x” 異常。
解決方案時(shí)直接用 import 語(yǔ)句導(dǎo)入:
# a.py
import b
def x():
print('x')
# b.py
import a
def y():
print('y')
a.x()
這題沒(méi)操作出來(lái).....
練習(xí)
0乍迄、問(wèn)大家一個(gè)問(wèn)題:Python 支持常量嗎?相信很多魚油的答案都是否定的褥伴,但實(shí)際上Python 內(nèi)建的命名空間是支持一小部分常量的,比如我們熟悉的True重慢,F(xiàn)alse,None等, 只是Python 沒(méi)有提供定義常量的直接方式而已似踱。那么這一題的要求是創(chuàng)建一個(gè) const 模塊,功能是讓 Python 支持常量囚戚。
說(shuō)到這里大家可能還是一頭霧水,沒(méi)關(guān)系弯淘,我們舉個(gè)例子吉懊。
test.py 是我們的測(cè)試代碼,內(nèi)容如下:
# const 模塊就是這道題要求我們自己寫的
# const 模塊用于讓Python 支持常量操作
const.NAME = "FishC"
print(const.NAME)
try:
# 嘗試修改變量
const.NAME = "FishC.com"
except TypeError as Err:
print(Err)
try:
# 變量名需要大寫
const.name = 'FishC'
except TypeError as Err:
print(Err)
執(zhí)行后的結(jié)果是:
>>>
FishC
常量無(wú)法改變借嗽!
常量名必須由大寫字母組成!
在const 模塊中我們到底做了什么浆竭,使得這個(gè)模塊這么有魔力呢惨寿?大家跟著小甲魚的提示邦泄,一步步來(lái)做你就懂了:
- 提示一:我們需要一個(gè)Const 類
- 提示二:重寫Const 類的一個(gè)魔法方法裂垦,指定當(dāng)實(shí)例對(duì)象的屬性被修改時(shí)的行為。
- 提示三:檢查該屬性是否已存在
- 提示四:檢查該屬性的名字是否為大寫
- 提示五:細(xì)心的魚油可能發(fā)現(xiàn)了特碳,怎么我們這個(gè)const 模塊導(dǎo)入之后就把它當(dāng)對(duì)象來(lái)使用(const.NAME = "FishC")了呢晕换?難道模塊也可以是一個(gè)對(duì)象午乓?沒(méi)錯(cuò)啦闸准,在Python 中無(wú)處不對(duì)象,到處都是你的對(duì)象夷家。使用以下方法可以將你的模塊與類A的對(duì)象掛鉤或辖。
'''sys.modules 是一個(gè)字典枣接,它包含了從Python 開始運(yùn)行
起缺谴,被導(dǎo)入的所有模塊。鍵就是模塊名湿蛔,值就是模塊對(duì)象'''
import sys
sys.modules[__name__] = A()
額...好像說(shuō)得有點(diǎn)太多了,大家一定要自己動(dòng)手先嘗試完成噢添谊。
代碼清單:
# 該模塊用于讓Python 支持常量操作
class Const:
def __setattr__(self,name,value):
if name in self.__dict__:
raise TypeError("常量無(wú)法改變察迟!")
if not name.isupper():
raise TypeError("常量名必須由大寫字母組成!")
self.__dict__[name] = value
import sys
sys.modules[__name__] = Const()
注: 這題再看看