通常來講,編程語言中,庫,包,模塊是同一種概念,是代碼組織方式
python中只有一種模塊對象類型,可是爲了模塊化組織的便利,提供了一個概念: 包
模塊(module):指的是python的源代碼文件
包(package):指的是模塊組織在一塊兒放入和包名同名的目錄及相關文件 python
能夠將代碼量較大的程序分割成多個有組織,彼此間獨立但又能互相交互的代碼片斷,這些自我包含的有組織的代碼段就是模塊linux
模塊在物理形式上表現爲以.py 結尾的代碼文件
一個文件被看作一個獨立的模塊,一個模塊也能夠被看作是一個文件
模塊的文件名就是模塊的名字加上擴展名.py程序員
每一個模塊都有本身的名稱空間
Python 容許「導入」其餘模塊以實現代碼重用,從而也實現了將獨立的代碼文件組織成更大的程序系統編程
Python 中,模塊也是對象
在一個模塊的頂層定義(全局變量)的全部變量都在被導入時成爲了被導入模塊的屬性網絡
一個Python程序一般包括一個頂層文件和其餘的模塊文件(0個,1個或多個)
頂層文件:包含了程序的主要控制流程
模塊文件:爲頂層文件或其餘模塊提供各類功能性組件
模塊首次導入(或重載)時,Python會當即執行模塊文件的頂層程序代碼(不在函數內的代碼),而位於函數體內的代碼直到函數被調用後纔會執行
Python自帶的模塊稱爲Python的標準庫模塊多線程
語句 | 含義 |
---|---|
import 模塊1[,模塊2,...] | 徹底導入 |
import ... as ... | 模塊別名 |
具體操做:框架
import 語句
1 找到指定模塊,初始化和加載它至內存中,若找不到,則拋出異常ImportError
2 import 所在的做用域的局部名稱空間中,增長了名稱和上一步建立的對象的關聯(在某個函數內部寫的impoer中的做用域中)編程語言
import 語句導入:ide
總結: 在當前模塊中導入另外一個模塊,找到單獨加載,單獨初始化,生成模塊對象,在本身的做用域內生成名稱,將對象和名稱進行映射,那個對象是單獨生成的,和本模塊(import所在的模塊)沒有多大關係,只是名稱和其對象進行了映射
模塊化
獲取指定名稱來收集對象的屬性和方法
獲取import 導入os.path的結果 ,此處只導入了os模塊
as 重名稱
總結 :
導入頂級模塊,其名稱對應的標識符加入到本地名稱空間中,並綁定到初始化後的模塊的位置
導入非頂級模塊,其頂級模塊對應的名稱標識符會加入到本地名稱空間中,導入的模塊必須使用徹底限定名成來訪問
若是使用了as,其後面的名稱會直接載入到本地名稱空間中,並直接綁定到導入的模塊對象
語句 | 含義 |
---|---|
from ... import | 部分導入 |
from ... import ... as ... | 別名 |
import 本質上只能導入模塊。而from中能夠對模塊中的屬性和方法內容進行導入操做
但其本質上仍是將from中指定的模塊所有都進行了初始化和加載操做
找到from子句中指定的模塊,加載並初始化它(注意不是導入)
對於impoer字句後面的名稱
1 先查看from字句導入的模塊是否具備該名稱屬性
2 若是不是,則嘗試導入該名稱的子模塊
3 尚未找到,則拋出ImportError異常
4 這個名稱保存到本地名稱空間中,若是有as字句,則使用as字句後的名稱
1 模塊名就是文件名
2 模塊名必須符合標識符要求,非數字開頭的數字,字母或下劃線,不能是其餘
3 不要使用系統模塊,以免衝突,除非你明確知道這個模塊名的用途
4 一般模塊名爲全小寫,下劃線來分割
使用sys.path 來查看模塊的搜索順序
顯示結果爲python模塊的路徑搜索順序
當加載一個模塊的時候,須要從這些模塊搜索路徑中從前向後一次查找,不搜索這些目錄的子目錄,搜索到就進行加載,搜索不到就拋出異常路徑能夠是字典,zip文件,egg文件
.egg文件,由setuptools庫建立的包,第三方經常使用的格式,添加了元數據(版本號,依賴項等)信息的zip文件
路徑順序爲
程序主目錄,程序運行的主程序腳本所在的目錄
PYTHONPATH 目錄,環境變量PYTHONPATH設置的目錄也是搜索模塊的路徑
標準庫目錄,python自帶的庫摩克所在目錄sys.path 是列表,能夠被修改,Linux自己是走PATH,所以須要加上./x 而Windows自己路徑就攜帶./
模塊是不能夠重複被導入的,重複導入是在浪費內存,其是在sys.modules中
從執行結果來看,不會產生重複導入的現象
全部加載的模塊都會記錄在sys.modules中。sys.modules存儲已經加載過全部模塊的字典
_name_ 每一個模塊都會定義一個_name_ 特殊變量來存儲當前模塊的名稱,若是不指定,默認爲源代碼文件名詞,若是有包則有限定名
解釋器初始化的時候,會初始化字典sys.modules(保存已加載的模塊),建立Builtins(全局函數,常量)模塊、__main__模塊,sys模塊,以及模塊搜索路徑sys.path
python是腳本語言,任何一個腳本均可以直接執行,也能夠做爲模塊被導入。
若是一個模塊可以被執行,則就是main模塊
當從標準輸入(命令行方式敲代碼),腳本或交互式讀取的時候,會將模塊的_name__設置爲_main\,模塊的頂層代碼就在_main__這個做用域中執行,將_name__修改成__main\
頂層代碼: 模塊中縮進最外層的代碼(當前解釋器執行的環境)
若是是import 導入的,其_name_ 默認就是模塊名建立一個自定義模塊,並獲取其模塊名
目標模塊中導入並打印相關模塊名
1 本模塊的功能測試
測試本模塊內的函數,類2 避免主模塊變動的反作用
頂層代碼,沒有封裝,主模塊使用沒有問題,可是,一旦有了新的主模塊,當前模塊要被導入,因爲源代碼沒有封裝,則會一併被執行。
屬性 | 含義 |
---|---|
_file_ | 字符串,源文件路徑 |
_cached_ | 字符串,編譯後的字節碼文件路徑 |
_spec_ | 顯示模塊的規範 |
_name_ | 模塊名 |
_package_ | 當模塊是包,同_name_,不然,能夠設置爲頂級模塊的空字符串 |
普通文件自然是一個模塊
建立一個普通文件夾,其是一個模塊,沒法在文件夾上寫代碼
添加一個模塊n
此模塊下面必須有一個.py的文件,其調用纔有意義
此模塊下建立.py文件爲n1.py
導入並查看其類型
其自帶_init_.py文件
導入結果對好比下
pycharm 中,建立Directory和建立python package 不一樣,前者是建立普通的目錄,後者是建立一個帶有_init_.py文件目錄,及包
包目錄下的py文件,子目錄都是其子模塊
三個模塊嵌套,都是package,都寫入print (_name_)用於獲取包名稱
在test中導入並查看以下
結論: 使用頻率高文件中,使用頻率多的應該放置在_init_.py中,由於模塊在初始化過程當中總會加載目錄中的_init_.py文件及其中的內容,但其不會執行和導入其餘相關子模塊
若目錄對應的_init_.py 不存在,則進行下一個對應的模塊,做爲一個好習慣是_init_.py文件必須有,python2中進行了限制,必須有,而python3中則限制不嚴,但建議必須存在
1 包可以更好的組織模塊,尤爲是大規模代碼不少,能夠拆分紅不少子模塊,便於使用某些功能就加載相應的子目錄
包目錄中_init_.py是包在第一次導入時就執行的,內容能夠爲空,也能夠是用於該包的初始化工做的代碼,最好不要刪除它(低版本不可刪除)
導入子模塊必定會加載父模塊,但導入父模塊必定不會加載子模塊
包之間只能使用.點號做爲間隔符,表示模塊及子目錄的層級關係
模塊也是封裝,如同類,函數,不過他可以封裝變量,類,函數
模塊就是名稱空間,其內部的頂層標識符,都是它的屬性,能夠經過_dict_ 或dir(module)查看
包也是模塊,但模塊不必定是包,包是特殊的模塊,是一種組織方式,它包含__path__屬性
凡是經過sys.path 找到的,都是絕對路徑
絕對導入
在import語句或者from導入模塊,模塊名稱最前面不是以.開頭的
絕對導入老是去搜索模塊搜索路徑中找
相對導入
只能在包內使用,且只能用在from語句中
使用.點號,表示當前目錄內
..表示上一級目錄注意:不要在頂層模塊中使用相對導入 (要參與運行的模塊)
在w2層級進行導入其父層級
在頂層目錄中導入子模塊
進行在test模塊中導入並查看
若在此頂層域中使用相對路徑,則不行,由於其沒法識別.和..等相關操做
定義__x和_y變量及z變量,並進行導入和訪問處理
結論:此處未進行相關的保護操做和換名操做
結論:結果是隻導入了公共屬性,私有屬性和保護變量屬性都不曾導入
_all_ 是一個可迭代對象,元素是字符串,每個元素都是一個模塊內的變量名
導入模塊以下
此處連以前的公共屬性也沒有了,只有對應寫入的__all__的屬性
若指定模塊
普通變量,保護變量,私有變量,特殊變量,都沒有被隱藏,也就是說模塊內部沒有私有變量,在模塊中定義不作特殊處理。
其和dir()顯示結果徹底相同,但dir是列表,而locals是字典類型
局部做用域,locals和dir都有局部做用域的概念
寫入子模塊導入
導入查看
1 使用from ... import * 導入
A 若是模塊中沒有_all_。from ... import * 只能導入非下劃線開頭的模塊的變量,若是是包,子模塊也不會導入,除非在_all__中設置,或者在_init\.py中使用相對導入
B 若是模塊中有_all_,from ... import * 只導入_all_ 列表中指定的名稱,哪怕這個名詞是下劃線開頭的,或者是子模塊
C from ... import * 方式導入,使用簡短,其反作用是會導入大量不須要使用的環境變量,甚至形成名稱衝突,而_all_ 能夠控制被導入模塊在這種導入方式下可以提供的變量名稱,就是爲了阻止from ... import *導入過多的模塊變量,從而避免衝突,所以,編寫模塊時,應該儘可能加入_all_
2 from module import name1,name2 導入
這種方式的導入是明確的,哪怕是導入子模塊,或者導入下劃線開頭的名稱,程序員能夠有控制和導入名稱和其對應的對象
w1 的_init_.py中定義一個參數z
在test1 中引入並對其進行修改
在test中進入並進行查看
結論:
模塊對象是同一個,所以模塊的變量也是同一個,對模塊變量的修改,會影響全部使用者,除非萬不得已,或明確知道本身在作什麼,不然不要修改模塊的變量
前面已經學習過猴子補丁,也能夠經過打補丁的方式,修改模塊的變量,類,函數等內容
python 的模塊或者源文件直接能夠複製到項目中,即可以導入使用了,但爲了更多項目的調用和使用,或者共享給別人,就須要進行打包,或者發佈到網絡上,便於其餘人使用。目的是爲了複用 。
本地使用的方式:
1 將模塊或包放置到sys.path的搜索路徑中便可
2 將此模塊所在的路徑加入到sys.path中便可,由於其是一個列表
1 distutils 官方庫distutils,使用安裝腳本setup.py來構建,安裝包
2 setuptools
是替代distutils 的加強版本工具,包括easy_install工具,使用ez_setup.py 文件,支持egg格式的構建和安裝
其可以提供查詢,下載,安裝,構建,發佈,管理包等包管理功能setuptools 再也不維護了。distribute是setuptools的替代品,其名字仍是setuptools
3 pip
pip 是目前包管理的實施標準,構建在setuptools之上,代替easy_install的同時也提供了豐富的包管理功能,通常的,都會攜帶setuptools和easy_install
4 wheel
提供bdist_wheel做爲setuptools的擴展命令,這個命令能夠用來生成wheel打包格式,pip 提供了一個wheel子命令來安裝wheel包,固然,須要先安裝wheel模塊,它可讓python庫以二進制形式安裝,而不須要在本地編譯。
test 中包含本身的初始化文件_init_.py及模塊test1.py 和包test2.py,test2.py中包含本身的初始化文件_init_.py和test21.py模塊。
其路徑在該包裝的最外層。
內容以下
#!/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全部的非目錄字母模塊打包 )
目錄結構
(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,而沒有穿透目錄進入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 )
刪除原來打包結果 以下
(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
build以後就能夠install了,直接運行以下
(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
其會自動添加到對應的第三方文件夾中,對應的是/root/.pyenv/versions/zhangbing/lib/python3.6/site-packages
建立源代碼的分發包
產生一個dist目錄,裏面生成一個帶版本號的壓縮包。
在其餘地方解壓這個文件,裏面有setup.py,就可使用python setup.py install 進行安裝了,也可使用pip install x.zip 直接安裝這個壓縮包
安裝相關依賴包
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
結果以下
(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包
(zhangbing) [root@python dist]# rpm -ivh test-0.1.0-1.noarch.rpm 準備中... ################################# [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
動態導入: 運行時根據用戶需求(提供字符串),找到模塊的資源動態加載起來,相較於以前的導入,其import在編譯期就決定的功能,是死的,很差用。
內建函數_import_()
相關參數
_import_(name,globals=None,locals=None,fromlist=(),level=0)
name,模塊名,global全局生效,locals局部生效
sys=_import_('sys') 等價於 import sys
結構以下
代碼以下
#!/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() # 此處調用模塊中的A類並進行實例化後調用show方法
test結果以下
將此方式移動進入主模塊中以下
#!/usr/bin/poython3.6 #conding:utf-8 # this is test if __name__ == "__main__": print(__import__('test1')) # 此處獲取到一個模塊對象 # 將模塊賦值 mod = __import__('test1') # 給模塊賦值 getattr(mod, 'A')().show() # 此處調用模塊中的A類並進行實例化後調用show方法
結果也是相同,但別人在調用此模塊時,其中的內容不會打印
進行函數化操做處理
#!/usr/bin/poython3.6 #conding:utf-8 # this is test def plugin_load(): mod=__import__('test1') getattr(mod,'A')().show() if __name__ == "__main__": # 在須要時進行動態加載 plugin_load()
結果以下:
上述方式只能每次加載一個,而不能實現多個加載,若想加載多個,則須要使用下面代碼
多個加載
#!/usr/bin/poython3.6 #conding:utf-8 # this is test def plugin_load(plugin_name:str,seq=":"): module,_,clas =plugin_name.partition(seq) #經過此處切割將獲取模塊名和對應的內部的類或函數的屬性名 mod=__import__(module) cls=getattr(mod,clas)().show() # 獲取屬性並進行調用其方法,此處的返回有業務需求決定 return cls if __name__ == "__main__": # 在須要時進行動態加載 # 進行調用處理 plugin_load("test1:A")
結果以下
#!/usr/bin/poython3.6 #conding:utf-8 # this is test def plugin_load(plugin_name:str,seq=":"): module,_,clas =plugin_name.partition(seq) #經過此處切割將獲取模塊名和對應的內部的類或函數的屬性名 mod=__import__(module) cls=getattr(mod,clas) # 獲取屬性並進行調用其方法,此處的返回有業務需求決定 return cls() # 此處返回一個實例 if __name__ == "__main__": # 在須要時進行動態加載 # 進行調用處理 plugin_load("test1:A").show()
結果以下
格式 importlib.import_module(name,package=None)
支持絕對導入和相對導入,若是是相對導入package必須設置
實例以下
#!/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) #經過此處切割將獲取模塊名和對應的內部的類或函數的屬性名 mod=importlib.import_module(module) cls=getattr(mod,clas) # 獲取屬性並進行調用其方法,此處的返回有業務需求決定 return cls() # 此處返回一個實例 if __name__ == "__main__": # 在須要時進行動態加載 # 進行調用處理 plugin_load("test1:A").show()
結果以下
反射: 運行時獲取類型的信息,能夠動態維護類型數據
動態import: 推薦使用importlib模塊,實現動態import模塊的能力
多線程:能夠開啓一個線程,等待用戶輸入,從而加載指定名稱的模塊
加載的類型
1 程序啓動時加載: 像pycharm這樣的工具,須要不少組件,這些組件多是插件,啓動的時候掃描固定的目錄加載插件
2 程序運行中: 程序運行過程當中,接受用戶指令或請求,啓動相應的插件
優缺點:
兩種方式各有利弊,若是插件不少,會致使程序啓動很慢。若是用戶須要時再加載,若是插件太大或者依賴太多,插件啓動慢。因此必須先加載經常使用的插件,其餘插件使用時,發現須要再插入
接口每每是暴露出來的功能,如模塊提供的函數或方法,加載模塊後調用這些函數完成功能,接口是一種規範,他約定了必須實現功能,但不關心如何實現此功能
插件是把模塊加載到系統中,運行它,加強當前系統功能,或者提供系統不具有的功能,每每插件技術應用在框架設計中,系統自己設計簡化、輕量級、實現基本功能後,其餘功能經過插件加入進來,方便擴展。