美文网首页初学者
Python中的包管理及插件化开发

Python中的包管理及插件化开发

作者: 我爱学python | 来源:发表于2020-03-23 20:47 被阅读0次

    一、包管理

    1、为什么使用包管理

    目的是为了便于共享。为了更多项目调用使用,或者共享给别人,就需要打包,目的是为了复用。

    Pypi(Python Package Index)公共的模块存储中心。https://pypi.python.org/pypi

    2、主要工具

    (1)distutils 官方标准库,使用安装脚本setup.py来构建、安装包。

    (2)setuptools 是替代distutils的增强版工具集,包含easy_install工具,使用ez_setup.py文件,支持egg格式的构建和安装。

    提供查询,下载,安装,构建,发布,管理等包管理功能。

    (3)Pip

    Pip是目前包管理的事实标准。

    构建在setuptools之上,替代easy_insall的,同样提供丰富的包管理功能。

    (4)wheel

    提供bdist_wheel作为setuptools的扩展命令,这个命令可以用来生成新打包格式wheel,

    Pip开始提供了一个wheel子命令来安装wheel包,必须先安装wheel模块,让Python库以二进制形式安装,不需要再本地编译。

    3、使用setup.py打包

    首先创建一个setup.py文件,

    内容:

    from distutils.core import setup
    
    setup(name='3',
          version='0.1.1',
          description = 'test',
          author='wcl',
          author_email='www.qq.com',
          packages = ['3']
    )
    
    #name:名字
    # version 版本
    # packages=[]打包列表
    # packages = ['3']指定以后,就会把所有的非目录子模块打包。
    # ['m','m.m1.m2.m3'] 逐级建立目录,但是只是把m的所有非目录子模块打包。后面的也打包
    #description 描述信息
    #author 作者
    #author_email作者邮件
    #url 包的主页,可以不写
    

    查询帮助命令:Python setup.py cmd -help

    4、build命令、编译

    创建一个build目录

    #Python setup.py build
    

    在项目目录下多了build目录,有一个lib子目录,lib下就是模块m的目录。

    所有的.py 文件全部被复制了,但是子目录没有被复制。

    构建了同样的目录结构,并只是拷贝了__ init __ .py 文件。

    build 得到的文件,直接拷贝到其他项目就可以使用了。

    打包的时候子包不要,模块还是要带上的。 setup.build。Packages后面写的是包名,而不是模块名。

    5、install命令,安装

    Build后就可以install,直接运行

    ###Python setup.py install
    

    如果没有build,会先build编译,然后安装。

    6、sdist命令,分发

    Sdist命令:

    ####Python setup.py sdist
    

    创建源代码的分发包

    产生一个dist目录,里面生成一个带版本号的压缩包。

    在其他地方解压缩文件,里面有setup.py 就可以直接使用 Python setup.py install 安装了,也可以 ##pip install xxxxxxxxxxx 直接使用pip安装这个压缩包。

    制作window是下的分发包:Python setup.py bdist_wininst.

    打包成rpm:Python setup.Py bdist_rpm

    也可以将写好的模块发布到公共的pipy上,也可以搭建pypi私服。

    模块名前后:优先级。

    7、wheel包

    安装wheel依赖

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    ## pip install wheel
    from distutils.core import setup
    from setuptools import setup
    setup(name='3',
          version='0.1.1',
          description = 'test',
          author='wcl',
          author_email='www.qq.com',
          packages = ['3']
    )
    

    分发一下,元代码打包成zip包。

    二、插件化开发

    动态导入

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

    1、__ import __()内建函数

    __import__ (name,globals=None,locals = None,fromlist=(),level=0)
    

    Name模块名

    Import语句本质上就是调用这个函数,但是不鼓励其直接使用,使用importlib.import_module().

    Sys = _import__(‘sys’)
    

    M2模块:

    class A:

    def show(self):
    
        print('A')
    

    M1:模块

    if __name__ == '__main__':
    
        mod = __import__('m2')
    
        cls = getattr(mod,'A')
    
        cls().show()
    

    动态的调用

    2、importlib.import_module()

    class A:

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
        def show(self):
            print('A') 
    
    import importlib
    def load(name:str,sep='.'):
        m,_,c = name.partition(sep)
        mod = importlib.import_module(m)
        cls = getattr(mod,c)
        return cls()
    
    if __name__ == '__main__':
        a = load('m2.A')
        a.show()
     
    A
    

    插件化的核心代码。

    3、插件化编程技术

    依赖的技术

    反射:运行时候获取类型的信息,可以动态维护类型数据。

    动态import:推荐使用importlib模块,实现动态import模块的能力。

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

    4、加载的时机

    1)程序启动时候。启动时候扫描固定的目录,加载插件。

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

    两个方式各有利弊,如果插件过多,会导致程序启动很慢,如果用户使用时候在加载,如果插件太大或者依赖多,插件将会启动慢。

    所以先加载常用的,必须的插件,其他插件使用时候,发现需要,动态载入。

    5、应用

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

    接口和插件的区别:

    接口往往是暴露出来的功能。例如模块提供的函数或方法,加载模块后调用这些函数完成功能。接口也是一种规范,约定了必须实现的功能(必须提供某名称的函数),但是不关心怎么实现这个功能。

    插件是吧模块加载到系统中,运行它,增强当前系统功能,或者提供系统不具备的功能,

    往往插件技术应用在框架设计中,系统本身设计简单化,轻量级,实现基本功能后,其他功能通过插件加入进来,方便扩展。

    三、基础知识补充的

    1、__ slots __

    问题的引出

    字典为了提升查询效率,必须利用空间换时间。

    一般来说一个对象,属性多一点,都存储在字典中便于查询,问题不大。

    对象数百万个。字典占用率就有些大了。

    只要slots定义的,就会阻止了实例的字典,没有了字典,里面只能出现定义的属性,没有定义的一律不能使用。

    class A:

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
        X = 1
        __slots__ = ('x','y')
        def __init__(self,x,y):
            self.x = x
            self.y = y
    
    
        def show(self):
            print(self.x,self.y)
    
    a = A(1,2)
    a.show()
    
    print('A',A.__dict__)
    # print(a.__dict__)  #字典被省略了
    print(a.__slots__)
     
    1 2
    
    A {'y': <member 'y' of 'A' objects>, 'show': <function A.show at 0x000000972DAF4BF8>, '__init__': <function A.__init__ at 0x000000972DAF4D08>, '__doc__': None, 'x': <member 'x' of 'A' objects>, '__slots__': ('x', 'y'), 'X': 1, '__module__': '__main__'}
    
    ('x', 'y')
    

    __ slota__告诉解释器,实例的属性豆角什么,一般来说,既要节约内存,最好还是使用元组比较好。

    而且实例不可以动态增加属性,类直接增加,因为slots是针对实例的。

    只能限制当前类的实例,不能继承使用。除非子类里面自己也是定义了slots.

    __ slots__ = 后面写元组比较好。

    应用场景:

    使用需要构建在数百万以上的对象,且内存容量较为紧张,实例的属性检查、固定缺不用动态增加的场景。

    2、未实现和未实现异常

    1)NotImplemented 未实现。是个值,单值。

    2)NotImplementedError 未实现异常。

    3)只有raise才是无参数的构造。

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    print(type(NotImplemented))
    
    print(type(NotImplementedError))
    
    # raise NotImplemented   #不可以使用,显示的是不属于异常类
    
    raise NotImplementedError
     
    

    3、运算符重载中的反向方法

    class A:
        def __init__(self,x):
            self.x = x
    
        def __add__(self, other):
            print(self,'add')
            return self.x + other.x
    
        def __iadd__(self, other):
            print(self,'iadd')
            return A(self.x + other.x)
    
        def __radd__(self, other):
            print(self,'radd')
            try:
                return self.x + other.x
            except AttributeError:
                try:
                    x = int(other)
                except:
                    x= 0
                return self.x + x
    
    
    a = A(4)
    # b = A(5)
    1 + a
     
    

    执行__ radd__,实现1+a的方法。

    字符串也是实现了__ add__ 方法,不过默认处理不了和其他类型的加法,所以就返回NotImplemented。

    相关文章

      网友评论

        本文标题:Python中的包管理及插件化开发

        本文链接:https://www.haomeiwen.com/subject/lvjgyhtx.html