溫馨提示×

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

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

36插件化開(kāi)發(fā)_slots_radd

發(fā)布時(shí)間:2020-06-25 19:29:23 來(lái)源:網(wǎng)絡(luò) 閱讀:365 作者:chaijowin 欄目:編程語(yǔ)言

?

?

目錄

插件化開(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

?

?

?

插件化開(kāi)發(fā)

?

例:notepad++中插件;firefox、chrome插件;eclipse;

?

動(dòng)態(tài)導(dǎo)入:

運(yùn)行時(shí),根據(jù)用戶(程序員)需求(如提供字符串),找到模塊的資源動(dòng)態(tài)加載起來(lái);

?

1、__import__(),內(nèi)建函數(shù);

2importlib.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()

?

?

?

2importlib.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ù):

依賴的技術(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è)功能;apiapplication 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ī)模,必須做成框架,越需要插件化思想;常用的先加載,不常用的懶加載;

?

?

?

__slots__

都是字典惹的禍,字典為了提升查詢效率,必須用空間換時(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}

?

?

?

未實(shí)現(xiàn)和未實(shí)現(xiàn)異常:

?

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())

?

?

?

運(yùn)算符重載中的反向方法:

?

例:

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)?? #不是1int)沒(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

?

?

?

?


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

免責(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)容。

AI