Python入門系列15 - 史上最詳細(xì)的包和模塊import講解篇
Python入門系列15

史上最詳細(xì)的包和模塊import講解篇
本篇文字圖片較多,閱讀時(shí)間不詳,能否讀完,純看你有沒有學(xué)習(xí)的心了?。?!
1
前言
在大量的代碼設(shè)計(jì)中,我們不可能將所有代碼都寫在一個(gè).py文件,所以有了包、模塊,而為了代碼可以重復(fù)利用(復(fù)用性),就有了類、函數(shù)的概念。類和函數(shù)在下次介紹。
2
python中的包
python中的包,對(duì)應(yīng)到計(jì)算機(jī)中,可以理解為文件夾,但是文件夾下必須有一個(gè)名為__init__.py的文件,若沒有此文件,python則會(huì)認(rèn)為其只是一個(gè)普通的文件夾。
打開pycharm,創(chuàng)建一個(gè)包,如下:


3
python中的模塊
python中的模塊就非常好理解了,實(shí)際上,之前所有的.py文件,我們都可以稱之為一個(gè)模塊。單獨(dú)的一個(gè)py文件就是一個(gè)模塊。


test1和test2不同區(qū)別就是test2是和package這個(gè)包是同級(jí)目錄,而test1是屬于package包的。
再來(lái)看下總的概念:

4
包和模塊的引入
1.模塊處于同級(jí)目錄(并且不在包下)
當(dāng)我們想在一個(gè)模塊中使用另一個(gè)模塊中的變量時(shí),如何操作呢?test2、test3處于同一級(jí)目錄。

我想在test3中引入test2的變量,test2.py中有個(gè)變量a = 2。



如上所示,只需要在當(dāng)前模塊,用import語(yǔ)句,即可導(dǎo)入模塊,具體使用的時(shí)候需要用模塊的名字.變量。
import 后面必須是模塊的名稱!------> import modul name
還有一種寫法如下圖pycharm中:

如上所示,只需要在當(dāng)前模塊,? ? ?from 模塊名字 import? 變量? ? ?
2.模塊處于同級(jí)目錄(在同一包下)
來(lái)看下,test1,test4都屬于package包下的模塊。

test1.py中有著字符串a(chǎn) = 'I am success!'

在test4.py中引用test1.py中的a,如何引用呢?
可以看到如下:

關(guān)鍵語(yǔ)法:import?包名.模塊名?as?別名
但是!?。。。。?!如果我們脫離pycharm,找到本機(jī)相應(yīng)的python目錄,通過cmd來(lái)運(yùn)行下,看下效果如何:


可以清晰的看到上圖,通過命令行模式執(zhí)行就會(huì)報(bào)錯(cuò)!錯(cuò)誤顯示模塊沒有被找到:沒有模塊叫'package'。這是為什么呢?在pycharm中通過右鍵run as運(yùn)行test4,可以看到控制臺(tái)成功輸出,而本地調(diào)用命令行的形式就報(bào)錯(cuò)了!
打開pycharm的setting,搜索 python console,右側(cè)其中有一項(xiàng),add content roots to pythonpath,默認(rèn)pycharm是勾選上此項(xiàng)的。此項(xiàng)的意思是將內(nèi)容的根路徑加到python的環(huán)境變量路徑下。

可以看到上圖下面代碼塊里寫著一堆代碼,正是這段代碼,我們才可以在pycharm中正確運(yùn)行。
我們可以在test1.py里來(lái)看下sys.path,順便打印看下結(jié)果。

pycharm控制臺(tái)輸出:
['F:\\pycharm\\python14\\package',?'F:\\pycharm\\python14',?
'D:\\python3.6\\python36.zip',?
'D:\\python3.6\\DLLs',?'D:\\python3.6\\lib',?'D:\\python3.6',?
'C:\\Users\\sy\\AppData\\Roaming\\Python\\Python36\\site-packages',?
'D:\\python3.6\\lib\\site-packages',?
'D:\\python3.6\\lib\\site-packages\\win32',?
'D:\\python3.6\\lib\\site-packages\\win32\\lib',
?'D:\\python3.6\\lib\\site-packages\\Pythonwin']
實(shí)際通過命令行輸出,應(yīng)該沒有'F:\\pycharm\\python14' 這一項(xiàng),因?yàn)檫@一項(xiàng)是pycharm中setting自動(dòng)加上的!
實(shí)際控制臺(tái)輸出:
['F:\\pycharm\\python14\\package',
'D:\\python3.6\\python36.zip',?
'D:\\python3.6\\DLLs',?'D:\\python3.6\\lib',?'D:\\python3.6',?
'C:\\Users\\sy\\AppData\\Roaming\\Python\\Python36\\site-packages',?
'D:\\python3.6\\lib\\site-packages',?
'D:\\python3.6\\lib\\site-packages\\win32',?
'D:\\python3.6\\lib\\site-packages\\win32\\lib',
?'D:\\python3.6\\lib\\site-packages\\Pythonwin']
sys.path是一個(gè)list。默認(rèn)情況下python導(dǎo)入文件或者模塊的話,他會(huì)先在sys.path里找模塊的路徑。如果沒有的話,程序就會(huì)報(bào)錯(cuò)。可以看到,sys路徑下有package的包名,而沒有test4.py中引用test1.py模塊。
而pycharm能夠成功運(yùn)行,正是因?yàn)樗呀?jīng)幫我們把項(xiàng)目的根路徑添加到了python的環(huán)境變量中。所以我們仿照其類似寫法也可以完成!
解決方案:
這里不得不說幾個(gè)重要的python自帶模塊了,如下:
①?
__file__ : python模塊自身的名稱
pycharm打印下__file__:
可以看到pycharm會(huì)將模塊的絕對(duì)路徑輸出到控制臺(tái)上。

在用命令行執(zhí)行下看看:

python額外小知識(shí):可以看到上圖有一個(gè)__pycache__的文件夾,這個(gè)文件夾在pycharm的目錄中,我們是看不到的,那么此文件夾的意義何在呢?點(diǎn)進(jìn)去看下:

Python程序運(yùn)行時(shí)不需要編譯成二進(jìn)制代碼,而直接從源碼運(yùn)行程序,簡(jiǎn)單來(lái)說是,Python解釋器將源碼轉(zhuǎn)換為字節(jié)碼,然后再由解釋器來(lái)執(zhí)行這些字節(jié)碼。而解釋器的具體工作:?
1、完成模塊的加載和鏈接。
2、將源代碼編譯為PyCodeObject對(duì)象(即字節(jié)碼),寫入內(nèi)存中,供CPU讀取。
3、從內(nèi)存中讀取并執(zhí)行,結(jié)束后將PyCodeObject寫回硬盤當(dāng)中,也就是復(fù)制到.pyc或.pyo文件中,以保存當(dāng)前目錄下所有腳本的字節(jié)碼文件。
4、若再次執(zhí)行該腳本,它先檢查【本地是否有上述字節(jié)碼文件】和【該字節(jié)碼文件的修改時(shí)間是否在其源文件之后】,是就直接執(zhí)行,否則重復(fù)上述步驟。
第一次執(zhí)行代碼的時(shí)候,Python解釋器已經(jīng)把編譯的字節(jié)碼放在
__pycache__文件夾中,這樣以后再次運(yùn)行的話,如果被調(diào)用的模塊未發(fā)生改變,那就直接跳過編譯這一步,直接去__pycache__文件夾中去運(yùn)行相關(guān)的 *.pyc 文件,大大縮短了項(xiàng)目運(yùn)行前的準(zhǔn)備時(shí)間。
CSDN來(lái)源:
https://blog.csdn.net/index20001/article/details/73501375
繼續(xù)回歸正題:
②
import?sys,os ??:? sys ,os模塊是python系統(tǒng)自帶模塊
os模塊:operate system 操作系統(tǒng)的意思,一般可以通過調(diào)用此模塊來(lái)對(duì)系統(tǒng)進(jìn)行相關(guān)操作
sys 模塊:system 系統(tǒng)的意思,通過此模塊來(lái)實(shí)現(xiàn)對(duì)python自定義包和模塊的導(dǎo)入
有了以上兩個(gè)知識(shí)點(diǎn),我們可以對(duì)test4.py進(jìn)行如下操作:
import?sys,os
print(__file__)
print(os.path.abspath(__file__))
print(os.path.dirname(os.path.abspath(__file__)))
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
因?yàn)閜ycharm會(huì)對(duì)__file__進(jìn)行路徑補(bǔ)充,所以我們用命令行來(lái)執(zhí)行test4.py:

可以看到上圖結(jié)果:
__file__?????????????模塊名字
test4.py???????????
os.path.abspath(__file__)?????模塊名字的絕對(duì)路徑
F:\pycharm\python14\package\test4.py
os.path.dirname(os.path.abspath(__file__))????模塊的包名絕對(duì)路徑
F:\pycharm\python14\package
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
F:\pycharm\python14???????????????????????????項(xiàng)目本身的絕對(duì)路徑
通過最后一步,我們可以將項(xiàng)目本身的路徑直接拼入python的sys下
base_path?=?os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(base_path)
驗(yàn)證究竟有沒有加到我們的python環(huán)境變量中,最終代碼為:
import?sys,?os
print(sys.path)
print(__file__)
print(os.path.abspath(__file__))
print(os.path.dirname(os.path.abspath(__file__)))
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
base_path?=?os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(base_path)
print(sys.path)
通過命令行執(zhí)行來(lái)看下:

有了以上的所有操作步驟,我們可以完美的將test1.py的a變量引入test4.py中了!來(lái)看下命令執(zhí)行:
import?sys,?os
base_path?=?os.path.dirname(os.path.dirname(
????????????????????????????os.path.abspath(__file__)))
sys.path.append(base_path)
----------------??sys拼接?一定要在自定義包引入之前定義???----------------------------------
import?package.test1?as?test1???????注意import的順序。
print(test1.a)

成功!
寫到這里涉及的知識(shí)點(diǎn)就已經(jīng)這么多了。。。繼續(xù)寫。。。
3.包處于同級(jí)目錄(包和包同級(jí),包1下的模塊引入包2下的模塊變量)

可以看到,通過from test3 import c,pycharm中是正常輸出的,控制臺(tái)是報(bào)錯(cuò)的!原因?qū)嶋H和“2.模塊處于同級(jí)目錄(在同一包下)”的解釋是一樣的,只需要在引入自定義包之前,將我們項(xiàng)目的根路徑加到python的系統(tǒng)變量中即可。
4.模塊處于不同級(jí)目錄(包和模塊同級(jí),模塊引入包下模塊的變量)



若屬于3的情況,可以看到,不需要對(duì)python系統(tǒng)進(jìn)行sys.append,可以正常使用import 或者 from 語(yǔ)句進(jìn)行導(dǎo)入。
5.模塊處于不同級(jí)目錄(包和模塊同級(jí),包下模塊引入與包模塊同級(jí)的變量)
test3.py 中有:
c = 123455666
在packeage下的test1.py調(diào)用:

可以看到,通過from test3 import c,pycharm中是正常輸出的,控制臺(tái)是報(bào)錯(cuò)的!原因?qū)嶋H和“2.模塊處于同級(jí)目錄(在同一包下)”的解釋是一樣的,只需要在引入自定義包之前,將我們項(xiàng)目的根路徑加到python的系統(tǒng)變量中即可。
import?sys,?os
base_path?=?os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(base_path)
from?test3?import?c
print(c)

5
模塊之前的相對(duì)引入
什么叫相對(duì)引入呢?相對(duì)路徑大家可能聽說過,相對(duì)引入和相對(duì)路徑是一個(gè)道理的,比如 .代表的是當(dāng)前目錄,..代表的是上級(jí)目錄,此處的寫法就是相對(duì)路徑,相對(duì)于某個(gè)文件來(lái)說,即相對(duì)!
實(shí)際上,在2.模塊處于同級(jí)目錄(在同一包下)中,還有一種相對(duì)引入的寫法,但是對(duì)于test4.py引入test1.py來(lái)說,不能直接運(yùn)行test4.py,否則會(huì)報(bào)錯(cuò)。來(lái)看下:

test1.py中有個(gè)a字符串:
test1.py
a?=?'I?am?success?!'
test4.py中,我用from .test1 import a來(lái)引入test1.py的變量a,注意,包下同級(jí)目錄,我使用的是.test1 ?!?。?!
test4.py
from?.test1?import?a
b?=?a?+?'I?am?test4.py?import?.test1'
如果此時(shí)我直接將test4.py運(yùn)行,并且打印b,就會(huì)報(bào)錯(cuò)!

ModuleNotFoundError:?No?module?named?'__main__.test1';?'__main__'?is?not?
a?package
如果此時(shí),我通過test2.py間接行調(diào)用test4.py中的b
from package.test4 import b
print(b)
無(wú)論是pycharm還是命令行,都是有成功運(yùn)行的:

也就是說python對(duì)于相對(duì)引入來(lái)說,主動(dòng)引入的函數(shù)不能作為主體去運(yùn)行!
6
pycharm中可能會(huì)遇到的import報(bào)錯(cuò)
有人可能會(huì)遇到,當(dāng)一個(gè)新項(xiàng)目導(dǎo)入到pycharm中,python代碼的import有可能會(huì)報(bào)錯(cuò),可以將項(xiàng)目設(shè)置為根路徑,這樣import錯(cuò)誤即可消失,操作如下:

7
包和模塊自身的額外小知識(shí)點(diǎn)
1. 關(guān)于包下的 __init__.py
init,中文意思是初始化的意思,而__init__.py實(shí)際上就是作為包名來(lái)配合的,當(dāng)我們調(diào)用一個(gè)包時(shí),第一步python就會(huì)去調(diào)用__init__.py模塊,所以,經(jīng)常我們可以將包下的__init__.py中放入一些需要初始化的操作。
舉個(gè)例子:

__init__.py:
init_a = 'I am __init__.py'
print(init_a)
在package包下定義了初始化的字符串。
而test2.py調(diào)用package下的test1.py中的a變量時(shí):
test2.py:
from package.test1 import a
print(a)
test1.py:
a = 'I am success !'
可以看到下圖運(yùn)行結(jié)果,先輸出了初始化模塊中的字符串:

2. 關(guān)于模塊中的限定變量寫法
依然是test2.py引入test1.py的變量:

test2.py:
from package.test1 import a,b,c
print(a)
print(b)
print(c)
test1.py:
__all__ = ['a','b']
a = 'I am success !'
b = 'I am fail !'
c = 'I am fuc*** ?you!!! !'
在test2中引入test1通過import單獨(dú)引入三個(gè)變量,運(yùn)行結(jié)果:

若將import 后面改成* ,則會(huì)限制變量。

而此處所說,就是因?yàn)樵趖est1.py中有著__all__ = []? ,這樣的寫法可以限定住import * 的限制,test4.py import *時(shí),則會(huì)被限制住罵人的語(yǔ)句!
8
import 模塊的萬(wàn)金油方法
上面說了這么多種情況,如果你實(shí)在是記不住,那么請(qǐng)記住一點(diǎn),萬(wàn)金油的import方式,就是在你所有模塊的入口模塊處,以下面代碼為例,將你項(xiàng)目本身的絕對(duì)路徑拼入到python 的系統(tǒng)path下,這樣自定義的包一定不會(huì)出錯(cuò)?。?!
import sys, os
base_path = os.path.dirname(os.path.dirname(
os.path.abspath(__file__)))
sys.path.append(base_path)
以上,就是史上最最最最最最,超超超超詳細(xì)的python模塊和包的引入詳解!?。。?!歡迎轉(zhuǎn)載!??!歡迎爆文?。。?!
