溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

python之模塊和包

發(fā)布時間:2020-07-24 19:36:24 來源:網(wǎng)絡(luò) 閱讀:1324 作者:長跑者1號 欄目:編程語言

一 Python模塊簡介

1 模塊化

一般來說,編程語言中,庫,包,模塊是同一種概念,是代碼組織方式
python中只有一種模塊對象類型,但是為了模塊化組織的便利,提供了一個概念: 包
模塊(module):指的是python的源代碼文件
包(package):指的是模塊組織在一起放入和包名同名的目錄及相關(guān)文件


可以將代碼量較大的程序分割成多個有組織,彼此間獨(dú)立但又能互相交互的代碼片段,這些自我包含的有組織的代碼段就是模塊


模塊在物理形式上表現(xiàn)為以.py 結(jié)尾的代碼文件
一個文件被看做一個獨(dú)立的模塊,一個模塊也可以被看做是一個文件
模塊的文件名就是模塊的名字加上擴(kuò)展名.py


2 模塊名稱空間

每個模塊都有自己的名稱空間
Python 允許“導(dǎo)入”其他模塊以實(shí)現(xiàn)代碼重用,從而也實(shí)現(xiàn)了將獨(dú)立的代碼文件組織成更大的程序系統(tǒng)


Python 中,模塊也是對象
在一個模塊的頂層定義(全局變量)的所有變量都在被導(dǎo)入時成為了被導(dǎo)入模塊的屬性

3 頂層文件和模塊文件

一個Python程序通常包括一個頂層文件和其他的模塊文件(0個,1個或多個)
頂層文件:包含了程序的主要控制流程
模塊文件:為頂層文件或其他模塊提供各種功能性組件
模塊首次導(dǎo)入(或重載)時,Python會立即執(zhí)行模塊文件的頂層程序代碼(不在函數(shù)內(nèi)的代碼),而位于函數(shù)體內(nèi)的代碼直到函數(shù)被調(diào)用后才會執(zhí)行
Python自帶的模塊稱為Python的標(biāo)準(zhǔn)庫模塊

二 import 和 from .. import 及自定義模塊

1 import 導(dǎo)入語句

語句 含義
import 模塊1[,模塊2,...] 完全導(dǎo)入
import ... as ... 模塊別名

具體操作:

import 語句
1 找到指定模塊,初始化和加載它至內(nèi)存中,若找不到,則拋出異常ImportError
2 import 所在的作用域的局部名稱空間中,增加了名稱和上一步創(chuàng)建的對象的關(guān)聯(lián)(在某個函數(shù)內(nèi)部寫的impoer中的作用域中)

import 語句導(dǎo)入:
python之模塊和包

總結(jié): 在當(dāng)前模塊中導(dǎo)入另一個模塊,找到單獨(dú)加載,單獨(dú)初始化,生成模塊對象,在自己的作用域內(nèi)生成名稱,將對象和名稱進(jìn)行映射,那個對象是單獨(dú)生成的,和本模塊(import所在的模塊)沒有多大關(guān)系,只是名稱和其對象進(jìn)行了映射


獲取指定名稱來收集對象的屬性和方法

python之模塊和包

獲取import 導(dǎo)入os.path的結(jié)果 ,此處只導(dǎo)入了os模塊

python之模塊和包

as 重名稱

python之模塊和包

總結(jié) :
導(dǎo)入頂級模塊,其名稱對應(yīng)的標(biāo)識符加入到本地名稱空間中,并綁定到初始化后的模塊的位置
導(dǎo)入非頂級模塊,其頂級模塊對應(yīng)的名稱標(biāo)識符會加入到本地名稱空間中,導(dǎo)入的模塊必須使用完全限定名成來訪問
如果使用了as,其后面的名稱會直接載入到本地名稱空間中,并直接綁定到導(dǎo)入的模塊對象

2 部分導(dǎo)入 (from ... import ...)

1 語法

語句 含義
from ... import 部分導(dǎo)入
from ... import ... as ... 別名

2 導(dǎo)入

python之模塊和包

import 本質(zhì)上只能導(dǎo)入模塊。而from中可以對模塊中的屬性和方法內(nèi)容進(jìn)行導(dǎo)入操作
但其本質(zhì)上還是將from中指定的模塊全部都進(jìn)行了初始化和加載操作

python之模塊和包

python之模塊和包

3 as 字句的使用

python之模塊和包

4 總結(jié)

找到from子句中指定的模塊,加載并初始化它(注意不是導(dǎo)入)
對于impoer字句后面的名稱
1 先查看from字句導(dǎo)入的模塊是否具有該名稱屬性
2 如果不是,則嘗試導(dǎo)入該名稱的子模塊
3 還沒有找到,則拋出ImportError異常
4 這個名稱保存到本地名稱空間中,如果有as字句,則使用as字句后的名稱

3 自定義模塊

1 自定義模塊test

python之模塊和包

2 import 方式導(dǎo)入模塊,其名詞邊界是模塊,不是方法或?qū)傩浴?/h4>

python之模塊和包

3 from ... import ... 方式導(dǎo)入模塊

python之模塊和包

4 自定義模塊命名規(guī)范:

1 模塊名就是文件名
2 模塊名必須符合標(biāo)識符要求,非數(shù)字開頭的數(shù)字,字母或下劃線,不能是其他
3 不要使用系統(tǒng)模塊,以避免沖突,除非你明確知道這個模塊名的用途
4 通常模塊名為全小寫,下劃線來分割

三 模塊相關(guān)屬性

1 模塊的搜索順序

使用sys.path 來查看模塊的搜索順序

python之模塊和包

顯示結(jié)果為python模塊的路徑搜索順序
當(dāng)加載一個模塊的時候,需要從這些模塊搜索路徑中從前向后一次查找,不搜索這些目錄的子目錄,搜索到就進(jìn)行加載,搜索不到就拋出異常

路徑可以是字典,zip文件,egg文件

.egg文件,由setuptools庫創(chuàng)建的包,第三方常用的格式,添加了元數(shù)據(jù)(版本號,依賴項(xiàng)等)信息的zip文件


路徑順序?yàn)?br/>程序主目錄,程序運(yùn)行的主程序腳本所在的目錄
PYTHONPATH 目錄,環(huán)境變量PYTHONPATH設(shè)置的目錄也是搜索模塊的路徑
標(biāo)準(zhǔn)庫目錄,python自帶的庫摩克所在目錄

sys.path 是列表,可以被修改,Linux本身是走PATH,因此需要加上./x 而Windows本身路徑就攜帶./

2 模塊的重復(fù)導(dǎo)入

模塊是不可以重復(fù)被導(dǎo)入的,重復(fù)導(dǎo)入是在浪費(fèi)內(nèi)存,其是在sys.modules中

python之模塊和包

從執(zhí)行結(jié)果來看,不會產(chǎn)生重復(fù)導(dǎo)入的現(xiàn)象
所有加載的模塊都會記錄在sys.modules中。sys.modules存儲已經(jīng)加載過所有模塊的字典

3 模塊的運(yùn)行

_name_ 每個模塊都會定義一個_name_ 特殊變量來存儲當(dāng)前模塊的名稱,如果不指定,默認(rèn)為源代碼文件名詞,如果有包則有限定名
解釋器初始化的時候,會初始化字典sys.modules(保存已加載的模塊),創(chuàng)建Builtins(全局函數(shù),常量)模塊、__main__模塊,sys模塊,以及模塊搜索路徑sys.path


python是腳本語言,任何一個腳本都可以直接執(zhí)行,也可以作為模塊被導(dǎo)入。


如果一個模塊能夠被執(zhí)行,則就是main模塊

當(dāng)從標(biāo)準(zhǔn)輸入(命令行方式敲代碼),腳本或交互式讀取的時候,會將模塊的_name__設(shè)置為_main\,模塊的頂層代碼就在_main__這個作用域中執(zhí)行,將_name__修改為__main\


頂層代碼: 模塊中縮進(jìn)最外層的代碼(當(dāng)前解釋器執(zhí)行的環(huán)境)
如果是import 導(dǎo)入的,其_name_ 默認(rèn)就是模塊名

創(chuàng)建一個自定義模塊,并獲取其模塊名

python之模塊和包

目標(biāo)模塊中導(dǎo)入并打印相關(guān)模塊名

python之模塊和包

4 if name== 'main': 用途

1 本模塊的功能測試
測試本模塊內(nèi)的函數(shù),類

2 避免主模塊變更的副作用
頂層代碼,沒有封裝,主模塊使用沒有問題,但是,一旦有了新的主模塊,當(dāng)前模塊要被導(dǎo)入,由于源代碼沒有封裝,則會一并被執(zhí)行。

5模塊內(nèi)部其他的屬性

屬性 含義
_file_ 字符串,源文件路徑
_cached_ 字符串,編譯后的字節(jié)碼文件路徑
_spec_ 顯示模塊的規(guī)范
_name_ 模塊名
_package_ 當(dāng)模塊是包,同_name_,否則,可以設(shè)置為頂級模塊的空字符串

python之模塊和包

四 模塊和包

1 模塊

普通文件天然是一個模塊
創(chuàng)建一個普通文件夾,其是一個模塊,無法在文件夾上寫代碼
添加一個模塊n

python之模塊和包

此模塊下面必須有一個.py的文件,其調(diào)用才有意義
此模塊下創(chuàng)建.py文件為n1.py

python之模塊和包

導(dǎo)入并查看其類型

python之模塊和包

2 創(chuàng)建包

python之模塊和包

其自帶_init_.py文件

python之模塊和包

導(dǎo)入結(jié)果對比如下

python之模塊和包

pycharm 中,創(chuàng)建Directory和創(chuàng)建python package 不同,前者是創(chuàng)建普通的目錄,后者是創(chuàng)建一個帶有_init_.py文件目錄,及包

3 子模塊

包目錄下的py文件,子目錄都是其子模塊

python之模塊和包

三個模塊嵌套,都是package,都寫入print (_name_)用于獲取包名稱

在test中導(dǎo)入并查看如下

python之模塊和包

結(jié)論: 使用頻率高文件中,使用頻率多的應(yīng)該放置在_init_.py中,因?yàn)槟K在初始化過程中總會加載目錄中的_init_.py文件及其中的內(nèi)容,但其不會執(zhí)行和導(dǎo)入其他相關(guān)子模塊


若目錄對應(yīng)的_init_.py 不存在,則進(jìn)行下一個對應(yīng)的模塊,作為一個好習(xí)慣是_init_.py文件必須有,python2中進(jìn)行了限制,必須有,而python3中則限制不嚴(yán),但建議必須存在

4 模塊和包的總結(jié):

1 包能夠更好的組織模塊,尤其是大規(guī)模代碼很多,可以拆分成很多子模塊,便于使用某些功能就加載相應(yīng)的子目錄


包目錄中_init_.py是包在第一次導(dǎo)入時就執(zhí)行的,內(nèi)容可以為空,也可以是用于該包的初始化工作的代碼,最好不要刪除它(低版本不可刪除)


導(dǎo)入子模塊一定會加載父模塊,但導(dǎo)入父模塊一定不會加載子模塊


包之間只能使用.點(diǎn)號作為間隔符,表示模塊及子目錄的層級關(guān)系


模塊也是封裝,如同類,函數(shù),不過他能夠封裝變量,類,函數(shù)


模塊就是名稱空間,其內(nèi)部的頂層標(biāo)識符,都是它的屬性,可以通過_dict_ 或dir(module)查看


包也是模塊,但模塊不一定是包,包是特殊的模塊,是一種組織方式,它包含__path__屬性

5 絕對導(dǎo)入和相對導(dǎo)入

1 概念

凡是通過sys.path 找到的,都是絕對路徑
絕對導(dǎo)入
在import語句或者from導(dǎo)入模塊,模塊名稱最前面不是以.開頭的
絕對導(dǎo)入總是去搜索模塊搜索路徑中找


相對導(dǎo)入

只能在包內(nèi)使用,且只能用在from語句中

使用.點(diǎn)號,表示當(dāng)前目錄內(nèi)
..表示上一級目錄

注意:不要在頂層模塊中使用相對導(dǎo)入 (要參與運(yùn)行的模塊)

2 導(dǎo)入實(shí)戰(zhàn)

在w2層級進(jìn)行導(dǎo)入其父層級

python之模塊和包

在頂層目錄中導(dǎo)入子模塊

python之模塊和包

進(jìn)行在test模塊中導(dǎo)入并查看

python之模塊和包

若在此頂層域中使用相對路徑,則不行,因?yàn)槠錈o法識別.和..等相關(guān)操作

6 訪問控制

1 定義變量

定義__x和_y變量及z變量,并進(jìn)行導(dǎo)入和訪問處理

python之模塊和包

2 導(dǎo)入并訪問查看

python之模塊和包

結(jié)論:此處未進(jìn)行相關(guān)的保護(hù)操作和換名操作

3 使用from w import * 導(dǎo)入

python之模塊和包

結(jié)論:結(jié)果是只導(dǎo)入了公共屬性,私有屬性和保護(hù)變量屬性都未曾導(dǎo)入

4 引入__all__模塊

_all_ 是一個可迭代對象,元素是字符串,每一個元素都是一個模塊內(nèi)的變量名

python之模塊和包

導(dǎo)入模塊如下

python之模塊和包

此處連之前的公共屬性也沒有了,只有對應(yīng)寫入的__all__的屬性

若指定模塊

python之模塊和包

普通變量,保護(hù)變量,私有變量,特殊變量,都沒有被隱藏,也就是說模塊內(nèi)部沒有私有變量,在模塊中定義不做特殊處理。

5 locals

python之模塊和包

其和dir()顯示結(jié)果完全相同,但dir是列表,而locals是字典類型

局部作用域,locals和dir都有局部作用域的概念

python之模塊和包

寫入子模塊導(dǎo)入

python之模塊和包

導(dǎo)入查看

python之模塊和包

6 總結(jié):

1 使用from ... import * 導(dǎo)入

A 如果模塊中沒有_all_。from ... import * 只能導(dǎo)入非下劃線開頭的模塊的變量,如果是包,子模塊也不會導(dǎo)入,除非在_all__中設(shè)置,或者在_init\.py中使用相對導(dǎo)入


B 如果模塊中有_all_,from ... import * 只導(dǎo)入_all_ 列表中指定的名稱,哪怕這個名詞是下劃線開頭的,或者是子模塊


C from ... import * 方式導(dǎo)入,使用簡短,其副作用是會導(dǎo)入大量不需要使用的環(huán)境變量,甚至造成名稱沖突,而_all_ 可以控制被導(dǎo)入模塊在這種導(dǎo)入方式下能夠提供的變量名稱,就是為了阻止from ... import *導(dǎo)入過多的模塊變量,從而避免沖突,因此,編寫模塊時,應(yīng)該盡量加入_all_


2 from module import name1,name2 導(dǎo)入

這種方式的導(dǎo)入是明確的,哪怕是導(dǎo)入子模塊,或者導(dǎo)入下劃線開頭的名稱,程序員可以有控制和導(dǎo)入名稱和其對應(yīng)的對象

7 模塊變量的修改

w1 的_init_.py中定義一個參數(shù)z

python之模塊和包

在test1 中引入并對其進(jìn)行修改

python之模塊和包

在test中進(jìn)入并進(jìn)行查看

python之模塊和包

結(jié)論:
模塊對象是同一個,因此模塊的變量也是同一個,對模塊變量的修改,會影響所有使用者,除非萬不得已,或明確知道自己在做什么,否則不要修改模塊的變量


前面已經(jīng)學(xué)習(xí)過猴子補(bǔ)丁,也可以通過打補(bǔ)丁的方式,修改模塊的變量,類,函數(shù)等內(nèi)容

五 包管理

1 為什么要使用包管理

python 的模塊或者源文件直接可以復(fù)制到項(xiàng)目中,便可以導(dǎo)入使用了,但為了更多項(xiàng)目的調(diào)用和使用,或者共享給別人,就需要進(jìn)行打包,或者發(fā)布到網(wǎng)絡(luò)上,便于其他人使用。目的是為了復(fù)用 。


本地使用的方式:
1 將模塊或包放置到sys.path的搜索路徑中即可
2 將此模塊所在的路徑加入到sys.path中即可,因?yàn)槠涫且粋€列表

2 主要工具

1 distutils 官方庫distutils,使用安裝腳本setup.py來構(gòu)建,安裝包


2 setuptools
是替代distutils 的增強(qiáng)版本工具,包括easy_install工具,使用ez_setup.py 文件,支持egg格式的構(gòu)建和安裝
其能夠提供查詢,下載,安裝,構(gòu)建,發(fā)布,管理包等包管理功能

setuptools 不再維護(hù)了。distribute是setuptools的替代品,其名字還是setuptools


3 pip
pip 是目前包管理的實(shí)施標(biāo)準(zhǔn),構(gòu)建在setuptools之上,代替easy_install的同時也提供了豐富的包管理功能,一般的,都會攜帶setuptools和easy_install


4 wheel

提供bdist_wheel作為setuptools的擴(kuò)展命令,這個命令可以用來生成wheel打包格式,pip 提供了一個wheel子命令來安裝wheel包,當(dāng)然,需要先安裝wheel模塊,它可以讓python庫以二進(jìn)制形式安裝,而不需要在本地編譯。

3 使用setup.py 打包

1 包結(jié)構(gòu)如下 :

python之模塊和包

test 中包含自己的初始化文件_init_.py及模塊test1.py 和包test2.py,test2.py中包含自己的初始化文件_init_.py和test21.py模塊。

2 創(chuàng)建setup.py文件

python之模塊和包

其路徑在該包裝的最外層。

內(nèi)容如下

#!/usr/bin/poython3.6
#conding:utf-8
from  distutils.core  import  setup

setup(
    name='test', # 名字
    version='0.1.0',  #版本
    description='Python test',  #打包列表
    author='zhang', # 作者
    author_email='12345678910@163.com',  #
    # url 表示包幫助文檔路徑
    packages=['test'] # 打包列表,指定test,會把w所有的非目錄字母模塊打包

)

3 打包

目錄結(jié)構(gòu)

python之模塊和包
python之模塊和包

(zhangbing) [root@python python3.5]# python setup.py build
running build
running build_py
creating build
creating build/lib
creating build/lib/test
copying test/test1.py -> build/lib/test
copying test/__init__.py -> build/lib/test
(zhangbing) [root@python python3.5]# ls
build  setup.py  test
(zhangbing) [root@python python3.5]# tree  build/
build/
└── lib
    └── test
        ├── __init__.py
        └── test1.py

2 directories, 2 files
(zhangbing) [root@python python3.5]# 

此處只包含了init.py和test1,而沒有穿透目錄進(jìn)入test2和test21

修改如下

#!/usr/bin/poython3.6
#conding:utf-8
from  distutils.core  import  setup

setup(
    name='test', # 名字
    version='0.1.0',  #版本
    description='Python test',  #打包列表
    author='zhang', # 作者
    author_email='12345678910@163.com',  #
    # url 表示包幫助文檔路徑
    packages=['test.test2'] # 此時只會打印test2中的test21.py和__init__.py

)

刪除原來打包結(jié)果 如下

(zhangbing) [root@python python3.5]# rm -rf build/
(zhangbing) [root@python python3.5]# ls
setup.py  test
(zhangbing) [root@python python3.5]# python setup.py build
running build
running build_py
creating build
creating build/lib
creating build/lib/test
creating build/lib/test/test2
copying test/test2/test21.py -> build/lib/test/test2
copying test/test2/__init__.py -> build/lib/test/test2
(zhangbing) [root@python python3.5]# tree  build/
build/
└── lib
    └── test
        └── test2
            ├── __init__.py
            └── test21.py

3 directories, 2 files

要使得全部打包,則需要

#!/usr/bin/poython3.6
#conding:utf-8
from  distutils.core  import  setup

setup(
    name='test', # 名字
    version='0.1.0',  #版本
    description='Python test',  #打包列表
    author='zhang', # 作者
    author_email='12345678910@163.com',  #
    # url 表示包幫助文檔路徑
    packages=['test','test.test2']

)

刪除上述build,如下

(zhangbing) [root@python python3.5]# rm -rf build/
(zhangbing) [root@python python3.5]# python setup.py build
running build
running build_py
creating build
creating build/lib
creating build/lib/test
copying test/test1.py -> build/lib/test
copying test/__init__.py -> build/lib/test
creating build/lib/test/test2
copying test/test2/test21.py -> build/lib/test/test2
copying test/test2/__init__.py -> build/lib/test/test2
(zhangbing) [root@python python3.5]# tree  build/
build/
└── lib
    └── test
        ├── __init__.py
        ├── test1.py
        └── test2
            ├── __init__.py
            └── test21.py

3 directories, 4 files

4 install 安裝命令

build之后就可以install了,直接運(yùn)行如下

(zhangbing) [root@python python3.5]# python  setup.py install 
running install
running build
running build_py
running install_lib
creating /root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test
copying build/lib/test/test1.py -> /root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test
copying build/lib/test/__init__.py -> /root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test
creating /root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/test2
copying build/lib/test/test2/test21.py -> /root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/test2
copying build/lib/test/test2/__init__.py -> /root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/test2
byte-compiling /root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/test1.py to test1.cpython-36.pyc
byte-compiling /root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/__init__.py to __init__.cpython-36.pyc
byte-compiling /root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/test2/test21.py to test21.cpython-36.pyc
byte-compiling /root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/test2/__init__.py to __init__.cpython-36.pyc
running install_egg_info
Writing /root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test-0.1.0-py3.6.egg-info
(zhangbing) [root@python python3.5]# ls
build  setup.py  test
(zhangbing) [root@python python3.5]# tree  /root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test
/root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test
├── __init__.py
├── __pycache__
│?? ├── __init__.cpython-36.pyc
│?? └── test1.cpython-36.pyc
├── test1.py
└── test2
    ├── __init__.py
    ├── __pycache__
    │?? ├── __init__.cpython-36.pyc
    │?? └── test21.cpython-36.pyc
    └── test21.py

3 directories, 8 files

其會自動添加到對應(yīng)的第三方文件夾中,對應(yīng)的是/root/.pyenv/versions/zhangbing/lib/python3.6/site-packages

4 命令分發(fā)

1 sdist命令簡介

創(chuàng)建源代碼的分發(fā)包
產(chǎn)生一個dist目錄,里面生成一個帶版本號的壓縮包。
在其他地方解壓這個文件,里面有setup.py,就可以使用python setup.py install 進(jìn)行安裝了,也可以使用pip install x.zip 直接安裝這個壓縮包

2 打包操作

安裝相關(guān)依賴包

yum -y install rpm-build

打包成rpm 如下

(zhangbing) [root@python python3.5]# rm -rf build/ dist/ MANIFEST 
(zhangbing) [root@python python3.5]# ls
setup.py  test
(zhangbing) [root@python python3.5]# python setup.py bdist_rpm
(zhangbing) [root@python python3.5]# python setup.py bdist_rpm
running bdist_rpm
creating build
creating build/bdist.linux-x86_64
creating build/bdist.linux-x86_64/rpm
creating build/bdist.linux-x86_64/rpm/SOURCES
creating build/bdist.linux-x86_64/rpm/SPECS
creating build/bdist.linux-x86_64/rpm/BUILD
creating build/bdist.linux-x86_64/rpm/RPMS
creating build/bdist.linux-x86_64/rpm/SRPMS
...
+ rm -rf test-0.1.0
+ exit 0
moving build/bdist.linux-x86_64/rpm/SRPMS/test-0.1.0-1.src.rpm -> dist
moving build/bdist.linux-x86_64/rpm/RPMS/noarch/test-0.1.0-1.noarch.rpm -> dist

結(jié)果如下

(zhangbing) [root@python python3.5]# ls
build  dist  MANIFEST  setup.py  test
(zhangbing) [root@python python3.5]# tree  dist/
dist/
├── test-0.1.0-1.noarch.rpm
├── test-0.1.0-1.src.rpm
└── test-0.1.0.tar.gz

0 directories, 3 files
(zhangbing) [root@python python3.5]# tree  build/
build/
└── bdist.linux-x86_64
    └── rpm
        ├── BUILD
        ├── BUILDROOT
        ├── RPMS
        │?? └── noarch
        ├── SOURCES
        │?? └── test-0.1.0.tar.gz
        ├── SPECS
        │?? └── test.spec
        └── SRPMS

9 directories, 2 files

此處在dict中生成了rpm包

3 安裝如下

(zhangbing) [root@python dist]# rpm  -ivh test-0.1.0-1.noarch.rpm 
準(zhǔn)備中...                          ################################# [100%]
正在升級/安裝...
   1:test-0.1.0-1                     ################################# [100%]

查看如下

(zhangbing) [root@python dist]# rpm -ql test
/root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test-0.1.0-py3.6.egg-info
/root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/__init__.py
/root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/__pycache__/__init__.cpython-36.opt-1.pyc
/root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/__pycache__/__init__.cpython-36.pyc
/root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/__pycache__/test1.cpython-36.opt-1.pyc
/root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/__pycache__/test1.cpython-36.pyc
/root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/test1.py
/root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/test2/__init__.py
/root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/test2/__pycache__/__init__.cpython-36.opt-1.pyc
/root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/test2/__pycache__/__init__.cpython-36.pyc
/root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/test2/__pycache__/test21.cpython-36.opt-1.pyc
/root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/test2/__pycache__/test21.cpython-36.pyc
/root/.pyenv/versions/zhangbing/lib/python3.6/site-packages/test/test2/test21.py

六 插件化開發(fā)基本概述

1 概述

動態(tài)導(dǎo)入: 運(yùn)行時根據(jù)用戶需求(提供字符串),找到模塊的資源動態(tài)加載起來,相較于之前的導(dǎo)入,其import在編譯期就決定的功能,是死的,不好用。


內(nèi)建函數(shù)_import_()
相關(guān)參數(shù)
_import_(name,globals=None,locals=None,fromlist=(),level=0)
name,模塊名,global全局生效,locals局部生效
sys=_import_('sys') 等價(jià)于 import sys

2 實(shí)例如下

結(jié)構(gòu)如下

python之模塊和包

代碼如下

#!/usr/bin/poython3.6
#conding:utf-8

# this  is  test1
class A:
    def show(self):
        print ('this is test1')
#!/usr/bin/poython3.6
#conding:utf-8
# this is test

print (__import__('test1'))  # 此處獲取到一個模塊對象
# 將模塊賦值
mod=__import__('test1') # 給模塊賦值
getattr(mod,'A')().show()  # 此處調(diào)用模塊中的A類并進(jìn)行實(shí)例化后調(diào)用show方法

test結(jié)果如下

python之模塊和包

將此方式移動進(jìn)入主模塊中如下

#!/usr/bin/poython3.6
#conding:utf-8
# this is test

if __name__ == "__main__":
    print(__import__('test1'))  # 此處獲取到一個模塊對象
    # 將模塊賦值
    mod = __import__('test1')  # 給模塊賦值
    getattr(mod, 'A')().show()  # 此處調(diào)用模塊中的A類并進(jìn)行實(shí)例化后調(diào)用show方法

結(jié)果也是相同,但別人在調(diào)用此模塊時,其中的內(nèi)容不會打印

進(jìn)行函數(shù)化操作處理

#!/usr/bin/poython3.6
#conding:utf-8
# this is test
def  plugin_load():
    mod=__import__('test1')
    getattr(mod,'A')().show()

if __name__ == "__main__":
    # 在需要時進(jìn)行動態(tài)加載
    plugin_load()

結(jié)果如下:
python之模塊和包

上述方式只能每次加載一個,而不能實(shí)現(xiàn)多個加載,若想加載多個,則需要使用下面代碼

多個加載

#!/usr/bin/poython3.6
#conding:utf-8
# this is test
def  plugin_load(plugin_name:str,seq=":"):
    module,_,clas =plugin_name.partition(seq)  #通過此處切割將獲取模塊名和對應(yīng)的內(nèi)部的類或函數(shù)的屬性名
    mod=__import__(module)
    cls=getattr(mod,clas)().show()  # 獲取屬性并進(jìn)行調(diào)用其方法,此處的返回有業(yè)務(wù)需求決定
    return cls

if __name__ == "__main__":
    # 在需要時進(jìn)行動態(tài)加載
    # 進(jìn)行調(diào)用處理
    plugin_load("test1:A")

結(jié)果如下

python之模塊和包

#!/usr/bin/poython3.6
#conding:utf-8
# this is test
def  plugin_load(plugin_name:str,seq=":"):
    module,_,clas =plugin_name.partition(seq)  #通過此處切割將獲取模塊名和對應(yīng)的內(nèi)部的類或函數(shù)的屬性名
    mod=__import__(module)
    cls=getattr(mod,clas) # 獲取屬性并進(jìn)行調(diào)用其方法,此處的返回有業(yè)務(wù)需求決定
    return cls() # 此處返回一個實(shí)例

if __name__ == "__main__":
    # 在需要時進(jìn)行動態(tài)加載
    # 進(jìn)行調(diào)用處理
    plugin_load("test1:A").show()

結(jié)果如下

python之模塊和包

3 import_module

格式 importlib.import_module(name,package=None)
支持絕對導(dǎo)入和相對導(dǎo)入,如果是相對導(dǎo)入package必須設(shè)置

實(shí)例如下

#!/usr/bin/poython3.6
#conding:utf-8
# this is test
import  importlib
def  plugin_load(plugin_name:str,seq=":"):
    module,_,clas =plugin_name.partition(seq)  #通過此處切割將獲取模塊名和對應(yīng)的內(nèi)部的類或函數(shù)的屬性名
    mod=importlib.import_module(module)
    cls=getattr(mod,clas) # 獲取屬性并進(jìn)行調(diào)用其方法,此處的返回有業(yè)務(wù)需求決定
    return cls() # 此處返回一個實(shí)例

if __name__ == "__main__":
    # 在需要時進(jìn)行動態(tài)加載
    # 進(jìn)行調(diào)用處理
    plugin_load("test1:A").show()

結(jié)果如下

python之模塊和包

4 插件化編程技術(shù)概述

1 依賴技術(shù)

反射: 運(yùn)行時獲取類型的信息,可以動態(tài)維護(hù)類型數(shù)據(jù)
動態(tài)import: 推薦使用importlib模塊,實(shí)現(xiàn)動態(tài)import模塊的能力
多線程:可以開啟一個線程,等待用戶輸入,從而加載指定名稱的模塊

2 加載時機(jī)

加載的類型
1 程序啟動時加載: 像pycharm這樣的工具,需要很多組件,這些組件可能是插件,啟動的時候掃描固定的目錄加載插件
2 程序運(yùn)行中: 程序運(yùn)行過程中,接受用戶指令或請求,啟動相應(yīng)的插件


優(yōu)缺點(diǎn):
兩種方式各有利弊,如果插件很多,會導(dǎo)致程序啟動很慢。如果用戶需要時再加載,如果插件太大或者依賴太多,插件啟動慢。所以必須先加載常用的插件,其他插件使用時,發(fā)現(xiàn)需要再插入

3 接口和插件區(qū)別

接口往往是暴露出來的功能,如模塊提供的函數(shù)或方法,加載模塊后調(diào)用這些函數(shù)完成功能,接口是一種規(guī)范,他約定了必須實(shí)現(xiàn)功能,但不關(guān)心如何實(shí)現(xiàn)此功能


插件是把模塊加載到系統(tǒng)中,運(yùn)行它,增強(qiáng)當(dāng)前系統(tǒng)功能,或者提供系統(tǒng)不具備的功能,往往插件技術(shù)應(yīng)用在框架設(shè)計(jì)中,系統(tǒng)本身設(shè)計(jì)簡化、輕量級、實(shí)現(xiàn)基本功能后,其他功能通過插件加入進(jìn)來,方便擴(kuò)展。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI