您好,登錄后才能下訂單哦!
?
?
目錄
插件化開(kāi)發(fā)... 1
動(dòng)態(tài)導(dǎo)入:... 1
插件化編程技術(shù):... 3
__slots__. 4
未實(shí)現(xiàn)和未實(shí)現(xiàn)異常:... 6
運(yùn)算符重載中的反向方法:... 6
?
?
?
?
例:notepad++中插件;firefox、chrome插件;eclipse;
?
運(yùn)行時(shí),根據(jù)用戶(程序員)需求(如提供字符串),找到模塊的資源動(dòng)態(tài)加載起來(lái);
?
1、__import__(),內(nèi)建函數(shù);
2、importlib.import_module(),import_module(name, package=None),支持絕對(duì)導(dǎo)入和相對(duì)導(dǎo)入,相對(duì)導(dǎo)入則必須要設(shè)置package;
?
import語(yǔ)句本質(zhì)上就是調(diào)用__import__()這個(gè)函數(shù),但不建議直接使用__import__(),建議使用importlib.import_module();
?
?
1、內(nèi)建函數(shù)__import__();
__import __(name,globals=None,locals=None,fromlist=(),level=0)
name,模塊名;
?
sys = __import__('sys')?? #等價(jià)于import sys,運(yùn)行時(shí)加載
?
例:
example_module_test1.py
class A:
??? def show(self):
??????? print(type(self).__name__)
??????? print(type(self.__module__))
?
example_plugins.py
if __name__ == '__main__':
??? mod = __import__('example_module_test1')?? #同import example_module_test1
??? getattr(mod,'A')().show()
輸出:
A
<class 'str'>
?
例:
def plugin_load():
??? mod = __import__('example_module_test1')?? #加載后會(huì)放到sys.modules里,搜索順序是在sys.path中找
??? # print(type(mod))??? #<class 'module'>
???????? getattr(mod,'A')().show()?? #getattr(object, name[, default]) -> value,等價(jià)于mod.A().show()
???????? # mod.A().show()
?
if __name__ == '__main__':
??? plugin_load()
輸出:
A
<class 'str'>
?
例:
def plugin_load(plugin_name:str,sep=':'):
??? m,_,c = plugin_name.partition(sep)
??? mod = __import__(m)
??? cls = getattr(mod,c)
??? return cls()
?
if __name__ == '__main__':
??? # plugin_load()
??? plugin_load('example_module_test1:A').show()
?
?
?
2、importlib.import_module():
?
例:
import importlib
def plugin_load(plugin_name:str,sep=':'):
??? # m,_,c = plugin_name.partition(sep)
??? m,c = plugin_name.split(sep)
??? mod = importlib.import_module(m)?? #推薦用此種,不要用__import__()
??? cls = getattr(mod,c)
??? return cls()
?
if __name__ == '__main__':
??? # plugin_load()
??? plugin_load('example_module_test1:A').show()
輸出:
A
<class 'str'>
?
?
依賴的技術(shù):
reflection,反射,運(yùn)行時(shí)獲取類型的信息,可動(dòng)態(tài)維護(hù)類型數(shù)據(jù);
動(dòng)態(tài)import,推薦使用importlib.import_module(),實(shí)現(xiàn)動(dòng)態(tài)import模塊的能力;
多線程,可開(kāi)啟一個(gè)線程,等待用戶輸入,從而加載指定名稱的模塊;
?
加載的時(shí)機(jī):
程序啟動(dòng)時(shí)?還是程序運(yùn)行中?
程序啟動(dòng)時(shí),像pycharm這樣的工具,需要很多組件,這些組件也可能是插件,啟動(dòng)的時(shí)候掃描固定的目錄,加載插件;
程序運(yùn)行時(shí),程序運(yùn)行過(guò)程中,接受用戶指令或請(qǐng)求,啟動(dòng)相應(yīng)的插件;
兩種方式各有利弊,如果插件過(guò)多,會(huì)導(dǎo)致程序啟動(dòng)很慢,如果用戶需要時(shí)加載,若插件太多或依賴多,插件也會(huì)啟動(dòng)慢;
所以先加載必須的、常用的插件,其它插件使用時(shí),發(fā)現(xiàn)需要,動(dòng)態(tài)載入;
?
應(yīng)用:
軟件的設(shè)計(jì)不可能盡善盡美,或在某些功能上,不可能做的專業(yè),需要專業(yè)的客戶自己增強(qiáng);
如notepadd++,它只需要做好一個(gè)文本編輯器就可以了,其它增強(qiáng)功能都通過(guò)插件的方式提供,如拼寫(xiě)檢查、HTML預(yù)覽、正則插件等;要定義規(guī)范、定義插件從哪里加載、如何加載、必須實(shí)現(xiàn)的功能等;
?
接口和插件區(qū)別:
接口往往是暴露出來(lái)的功能,接口指的是操作(方法|函數(shù)),如模塊提供了函數(shù)和方法,加載模塊后調(diào)用這些函數(shù)完成功能;接口也是一種規(guī)范,它約定了必須實(shí)現(xiàn)的功能(必須提供某名稱的函數(shù)),但不關(guān)心怎么實(shí)現(xiàn)這個(gè)功能;api,application program interface;url指向的是后臺(tái)應(yīng)用中某個(gè)類的方法;
插件是把模塊加載到系統(tǒng)中,運(yùn)行它,增強(qiáng)當(dāng)前系統(tǒng)功能,或提供系統(tǒng)不具備的功能,往往插件技術(shù)應(yīng)用在框架設(shè)計(jì)中,系統(tǒng)本身設(shè)計(jì)簡(jiǎn)單化、輕量級(jí)、實(shí)現(xiàn)基本功能后,其它功能通過(guò)插件加入進(jìn)來(lái),方便擴(kuò)展;
?
銷售:
插件化需求,旗艦版、家庭版;
另一些軟件把相應(yīng)功能的菜單隱藏了,通過(guò)序列號(hào)可打開(kāi)隱藏的這些功能;
軟件達(dá)到一定規(guī)模,必須做成框架,越需要插件化思想;常用的先加載,不常用的懶加載;
?
?
?
都是字典惹的禍,字典為了提升查詢效率,必須用空間換時(shí)間(為了hash得占用一定的空間);
一般來(lái)說(shuō),一個(gè)對(duì)象,屬性都存儲(chǔ)在字典中便于查詢,問(wèn)題不大;但如果數(shù)百萬(wàn)個(gè)對(duì)象,字典就有點(diǎn)大了;這個(gè)時(shí)候,能否把屬性字典__dict__給省了;py提供了__slots__;
可理解為就給這幾個(gè)槽位放東西,用__slots__規(guī)定有什么樣的屬性;
?
實(shí)例用;標(biāo)準(zhǔn)庫(kù)中用得多;
限制實(shí)例暴露出的屬性供別人使用;
類屬性不影響;
?
應(yīng)用場(chǎng)景:
未來(lái)可能產(chǎn)生大量實(shí)例,這些實(shí)例中有不需要的屬性,用__slots__暴露出可用的屬性,且用元組形式列出(是可迭代對(duì)象均可,一個(gè)屬性時(shí)字符串也可);
當(dāng)要使用數(shù)百萬(wàn)個(gè)對(duì)象,且內(nèi)存容量較為緊張的場(chǎng)景;
?
__slots__ = 'p1'或__slots__ = 'p1','p2'均可,建議用元組形式__slots__ = ('p1','p2'),__slots__告訴解釋器,實(shí)例的屬性都叫什么,一般來(lái)說(shuō)既然要節(jié)約內(nèi)存,最好還是用元組,一旦類提供了__slots__就阻止實(shí)例產(chǎn)生__dict__來(lái)保存實(shí)例的屬性;
?
繼承類的實(shí)例不受__slots__影響,__slots__管不到自己的子類,控制不了子類;__slots__不影響子類實(shí)例,不會(huì)繼承下去,除非子類里面自己也定義了__slots__;__slots__一般在子類上用,而且是最下面的子類,父類功能不全;
?
例:
class A:
??? x = 123
??? __slots__ = ('p1','p2')?? #__slots__ = 'p1'或__slots__ = 'p1','p2'均可,建議用元組形式__slots__ = ('p1','p2'),__slots__告訴解釋器,實(shí)例的屬性都叫什么,一般來(lái)說(shuō)既然要節(jié)約內(nèi)存,最好還是用元組,一旦類提供了__slots__就阻止實(shí)例產(chǎn)生__dict__來(lái)保存實(shí)例的屬性
??? def __init__(self):
??????? self.p1 = 1
??????? self.p2 = 2
?
??? def showme(self):
??????? print('I am A.{}'.format(self.p1))
?
print(A.__dict__)
# print(A().__dict__)?? #X,實(shí)例屬性被限制,實(shí)例的__dict__消失了
print(A().__slots__)
a = A()
a.p2 = 200
# a.x = 300?? # AttributeError: 'A' object attribute 'x' is read-only
A.x = 500
輸出:
{'__module__': '__main__', 'x': 123, '__slots__': ('p1', 'p2'), '__init__': <function A.__init__ at 0x7fa9ba0be0d0>, 'showme': <function A.showme at 0x7fa9ba0be158>, 'p1': <member 'p1' of 'A' objects>, 'p2': <member 'p2' of 'A' objects>, '__doc__': None}
('p1', 'p2')
1 200
?
例:
class A:
??? x = 123
??? __slots__ = ('p1','p2')
??? def __init__(self):
??????? self.p1 = 1
??????? self.p2 = 2
?
??? def showme(self):
??????? print('I am A.{}'.format(self.p1))
?
class B(A):
??? def __init__(self):
??????? self.b1 = 500
?
print(B().__dict__)?? #繼承類的實(shí)例不受__slots__影響,__slots__管不到自己的子類,控制不了子類;__slots__不影響子類實(shí)例,不會(huì)繼承下去,除非子類里面自己也定義了__slots__;__slots__一般在子類上用,而且是最下面的子類,父類功能不全
輸出:
{'b1': 500}
?
?
?
?
print(type(NotImplemented))
print(type(NotImplementedError))
輸出:
<class 'NotImplementedType'>?? #是個(gè)值,單值,是NotImplementedType類的實(shí)例
<class 'type'>?? #是類型,是異常,返回type,父類RuntimeError-->父類Exception
?
例:
class A:
??? def showme(self):
??????? raise NotImplementedError
?
print(A().showme())
?
?
?
?
例:
class Add:
??? def __init__(self,x:int):
??????? self.x = x
?
??? def __add__(self, other):
??????? print('__add__',self)
??????? # return self.x + other.x
??????? return self.x + other
??? # def __add__(self, other):
??? #???? print('__add__',self)
??? #???? try:
??? #???????? res = self.x + other.x
??? #???? except:
??? #???????? try:
??? #???????????? o = int(other)
??? #???????? except:
??? #???????????? o = 0
??? #???????? res = self.x + o
??? #???? return res
??? # def __add__(self, other):
??? #???? print('__add__',self)
??? #???? try:
??? #???????? o = int(other.x)
??? #???? except:
??? #???????? o = 0
??? #???? return self.x + 0
?
??? def __iadd__(self, other):
??????? print('__iadd__',self)
??????? return self.x + other.x
?
??? def __radd__(self, other):
??????? print('__radd__',self)
??????? # return self.x + other.x
??????? return self + other
?
a = Add(4)
b = Add('abc')
# print(a+b)
# print(a+=b)
# print(b+a)
# print(a+1)?? #不是1(int)沒(méi)有實(shí)現(xiàn)__add__(),int中有所有的方法
print(1+a)?? #1+a等價(jià)于1.__add__(a),而Int類實(shí)現(xiàn)了__add__(),不過(guò)這個(gè)方法對(duì)于這種加法的返回值是NotImplemented,解釋器發(fā)現(xiàn)是這個(gè)值,就會(huì)發(fā)起對(duì)第二操作對(duì)象的__radd__()調(diào)用
輸出:
__radd__ <__main__.Add object at 0x7f42d83acfd0>
__add__ <__main__.Add object at 0x7f42d83acfd0>
5
?
例:
class Add:
??? def __init__(self,x:int):
??????? self.x = x
?
??? def __add__(self, other):
??????? print('__add__',self)
??????? return self.x + other.x
?
??? def __iadd__(self, other):
??????? print('__iadd__',self)
??????? return self.x + other.x
?
??? def __radd__(self, other):
??????? print('__radd__',self)
??????? # return self.x + other.x
? ??????return self + other
?
class B:
??? def __init__(self,x):
??????? self.x = x
?
a = Add(4)
b = B(6)
print(a+b)
print(b+a)?? #b+a等價(jià)于b.__add__(a),但類B沒(méi)有實(shí)現(xiàn)__add__(),就去找a的__radd__()方法
輸出:
__add__ <__main__.Add object at 0x7f02a03f7160>
10
__radd__ <__main__.Add object at 0x7f02a03f7160>
__add__ <__main__.Add object at 0x7f02a03f7160>
10
?
?
?
?
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。