36插件化开发_slots_radd

 

创新互联专注为客户提供全方位的互联网综合服务,包含不限于成都网站设计、成都网站制作、濉溪网络推广、小程序开发、濉溪网络营销、濉溪企业策划、濉溪品牌公关、搜索引擎seo、人物专访、企业宣传片、企业代运营等,从售前售中售后,我们都将竭诚为您服务,您的肯定,是我们最大的嘉奖;创新互联为所有大学生创业者提供濉溪建站搭建服务,24小时服务热线:18982081108,官方网址:www.cdcxhl.com

 

目录

插件化开发...1

动态导入:...1

插件化编程技术:...3

__slots__.4

未实现和未实现异常:...6

运算符重载中的反向方法:...6

 

 

 

插件化开发

 

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

 

动态导入:

运行时,根据用户(程序员)需求(如提供字符串),找到模块的资源动态加载起来;

 

1、__import__(),内建函数;

2、importlib.import_module(),import_module(name, package=None),支持绝对导入和相对导入,相对导入则必须要设置package;

 

import语句本质上就是调用__import__()这个函数,但不建议直接使用__import__(),建议使用importlib.import_module();

 

 

1、内建函数__import__();

__import __(name,globals=None,locals=None,fromlist=(),level=0)

name,模块名;

 

sys = __import__('sys')   #等价于import sys,运行时加载

 

例:

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

 

例:

def plugin_load():

    mod = __import__('example_module_test1')   #加载后会放到sys.modules里,搜索顺序是在sys.path中找

    # print(type(mod))    #

         getattr(mod,'A')().show()   #getattr(object, name[, default]) -> value,等价于mod.A().show()

         # mod.A().show()

 

if __name__ == '__main__':

    plugin_load()

输出:

A

 

例:

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

 

 

插件化编程技术:

依赖的技术:

reflection,反射,运行时获取类型的信息,可动态维护类型数据;

动态import,推荐使用importlib.import_module(),实现动态import模块的能力;

多线程,可开启一个线程,等待用户输入,从而加载指定名称的模块;

 

加载的时机:

程序启动时?还是程序运行中?

程序启动时,像pycharm这样的工具,需要很多组件,这些组件也可能是插件,启动的时候扫描固定的目录,加载插件;

程序运行时,程序运行过程中,接受用户指令或请求,启动相应的插件;

两种方式各有利弊,如果插件过多,会导致程序启动很慢,如果用户需要时加载,若插件太多或依赖多,插件也会启动慢;

所以先加载必须的、常用的插件,其它插件使用时,发现需要,动态载入;

 

应用:

软件的设计不可能尽善尽美,或在某些功能上,不可能做的专业,需要专业的客户自己增强;

如notepadd++,它只需要做好一个文本编辑器就可以了,其它增强功能都通过插件的方式提供,如拼写检查、HTML预览、正则插件等;要定义规范、定义插件从哪里加载、如何加载、必须实现的功能等;

 

接口和插件区别:

接口往往是暴露出来的功能,接口指的是操作(方法|函数),如模块提供了函数和方法,加载模块后调用这些函数完成功能;接口也是一种规范,它约定了必须实现的功能(必须提供某名称的函数),但不关心怎么实现这个功能;api,application program interface;url指向的是后台应用中某个类的方法;

插件是把模块加载到系统中,运行它,增强当前系统功能,或提供系统不具备的功能,往往插件技术应用在框架设计中,系统本身设计简单化、轻量级、实现基本功能后,其它功能通过插件加入进来,方便扩展;

 

销售:

插件化需求,旗舰版、家庭版;

另一些软件把相应功能的菜单隐藏了,通过序列号可打开隐藏的这些功能;

软件达到一定规模,必须做成框架,越需要插件化思想;常用的先加载,不常用的懒加载;

 

 

 

__slots__

都是字典惹的祸,字典为了提升查询效率,必须用空间换时间(为了hash得占用一定的空间);

一般来说,一个对象,属性都存储在字典中便于查询,问题不大;但如果数百万个对象,字典就有点大了;这个时候,能否把属性字典__dict__给省了;py提供了__slots__;

可理解为就给这几个槽位放东西,用__slots__规定有什么样的属性;

 

实例用;标准库中用得多;

限制实例暴露出的属性供别人使用;

类属性不影响;

 

应用场景:

未来可能产生大量实例,这些实例中有不需要的属性,用__slots__暴露出可用的属性,且用元组形式列出(是可迭代对象均可,一个属性时字符串也可);

当要使用数百万个对象,且内存容量较为紧张的场景;

 

__slots__ = 'p1'或__slots__ = 'p1','p2'均可,建议用元组形式__slots__ = ('p1','p2'),__slots__告诉解释器,实例的属性都叫什么,一般来说既然要节约内存,最好还是用元组,一旦类提供了__slots__就阻止实例产生__dict__来保存实例的属性;

 

继承类的实例不受__slots__影响,__slots__管不到自己的子类,控制不了子类;__slots__不影响子类实例,不会继承下去,除非子类里面自己也定义了__slots__;__slots__一般在子类上用,而且是最下面的子类,父类功能不全;

 

例:

class A:

    x = 123

    __slots__ = ('p1','p2')   #__slots__ = 'p1'或__slots__ = 'p1','p2'均可,建议用元组形式__slots__ = ('p1','p2'),__slots__告诉解释器,实例的属性都叫什么,一般来说既然要节约内存,最好还是用元组,一旦类提供了__slots__就阻止实例产生__dict__来保存实例的属性

    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,实例属性被限制,实例的__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__': , 'showme': , 'p1': , 'p2': , '__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__)   #继承类的实例不受__slots__影响,__slots__管不到自己的子类,控制不了子类;__slots__不影响子类实例,不会继承下去,除非子类里面自己也定义了__slots__;__slots__一般在子类上用,而且是最下面的子类,父类功能不全

输出:

{'b1': 500}

 

 

 

未实现和未实现异常:

 

print(type(NotImplemented))

print(type(NotImplementedError))

输出:

   #是个值,单值,是NotImplementedType类的实例

   #是类型,是异常,返回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)没有实现__add__(),int中有所有的方法

print(1+a)   #1+a等价于1.__add__(a),而Int类实现了__add__(),不过这个方法对于这种加法的返回值是NotImplemented,解释器发现是这个值,就会发起对第二操作对象的__radd__()调用

输出:

__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等价于b.__add__(a),但类B没有实现__add__(),就去找a的__radd__()方法

输出:

__add__ <__main__.Add object at 0x7f02a03f7160>

10

__radd__ <__main__.Add object at 0x7f02a03f7160>

__add__ <__main__.Add object at 0x7f02a03f7160>

10

 

 

 

 


分享标题:36插件化开发_slots_radd
标题网址:http://myzitong.com/article/gpcehh.html