目的是为了便于共享。为了更多项目调用使用,或者共享给别人,就须要打包,目的是为了复用。python
Pypi(Python Package Index)公共的模块存储中心。https://pypi.python.org/pypi编程
(1)distutils 官方标准库,使用安装脚本setup.py来构建、安装包。多线程
(2)setuptools 是替代distutils的加强版工具集,包含easy_install工具,使用ez_setup.py文件,支持egg格式的构建和安装。框架
提供查询,下载,安装,构建,发布,管理等包管理功能。函数
(3)Pip工具
Pip是目前包管理的事实标准。ui
构建在setuptools之上,替代easy_insall的,一样提供丰富的包管理功能。url
(4)wheel插件
提供bdist_wheel做为setuptools的扩展命令,这个命令能够用来生成新打包格式wheel,线程
Pip开始提供了一个wheel子命令来安装wheel包,必须先安装wheel模块,让Python库以二进制形式安装,不须要再本地编译。
首先建立一个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
建立一个build目录
#Python setup.py build
在项目目录下多了build目录,有一个lib子目录,lib下就是模块m的目录。
全部的.py 文件所有被复制了,可是子目录没有被复制。
构建了一样的目录结构,并只是拷贝了__init__.py 文件。
build 获得的文件,直接拷贝到其余项目就可使用了。
打包的时候子包不要,模块仍是要带上的。 setup.build。Packages后面写的是包名,而不是模块名。
Build后就能够install,直接运行
###Python setup.py install
若是没有build,会先build编译,而后安装。
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私服。
模块名先后:优先级。
七、wheel包
安装wheel依赖
## 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包。
动态导入
运行时候,根据用户需求(提供字符串),找到模块的资源动态加载起来。
__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()
动态的调用
class A:
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
插件化的核心代码。
依赖的技术
反射:运行时候获取类型的信息,能够动态维护类型数据。
动态import:推荐使用importlib模块,实现动态import模块的能力。
多线程:能够开启一个线程。等待用户输入,从而加载指定名称的模块。
1)程序启动时候。启动时候扫描固定的目录,加载插件。
2)程序运行时。程序运行中,接受用户指令或请求,启动相应的插件。
两个方式各有利弊,若是插件过多,会致使程序启动很慢,若是用户使用时候在加载,若是插件太大或者依赖多,插件将会启动慢。
因此先加载经常使用的,必须的插件,其余插件使用时候,发现须要,动态载入。
软件的设计不可能尽善尽美,或者在某些功能上,不可能作的太专业了,须要专业的客户本身加强。
接口和插件的区别:
接口每每是暴露出来的功能。例如模块提供的函数或方法,加载模块后调用这些函数完成功能。接口也是一种规范,约定了必须实现的功能(必须提供某名称的函数),可是不关心怎么实现这个功能。
插件是吧模块加载到系统中,运行它,加强当前系统功能,或者提供系统不具有的功能,
每每插件技术应用在框架设计中,系统自己设计简单化,轻量级,实现基本功能后,其余功能经过插件加入进来,方便扩展。
问题的引出
字典为了提高查询效率,必须利用空间换时间。
通常来讲一个对象,属性多一点,都存储在字典中便于查询,问题不大。
对象数百万个。字典占用率就有些大了。
只要slots定义的,就会阻止了实例的字典,没有了字典,里面只能出现定义的属性,没有定义的一概不能使用。
class A:
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__ = 后面写元组比较好。
应用场景:
使用须要构建在数百万以上的对象,且内存容量较为紧张,实例的属性检查、固定缺不用动态增长的场景。
1)NotImplemented 未实现。是个值,单值。
2)NotImplementedError 未实现异常。
3)只有raise才是无参数的构造。
print(type(NotImplemented))
print(type(NotImplementedError))
# raise NotImplemented #不可使用,显示的是不属于异常类
raise NotImplementedError
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。