Python高级编程——速查笔记 第3、4、5、6章
- Python高级编程 (速查笔记 第3、4、5、6章)
- 第三章 最佳语法实践——*类级别以上*
- 1. 子类化内置类型
- 2. 访问超类中的方法
- 3. 高级属性访问模式
- 4. 元编程
- 第四章 选择好的名称
- 1 PEP 8 与命名最佳实践
- 2. 命名风格;
- 3. 命名指南
- 4. 最佳实践
- 5. 类的命名
- 6. 模块和包的名称
- 7. 辅助工具
- 第五章 编写一个包
- 1. 创建一个包
- 2. 命名空间包
- 3. 上传一个包
- 4. 独立可执行文件(单独打包)
- 5. 总结
- 第六章. 部署代码
- 1. 十二要素应用
- 2. fabric(2)自动化部署
- 3.自有包索引或者索引镜像
- 4.常见约定与实践
- 5. 代码检测与监控
- 6. 小结
这本《Python 高级编程》 是为数不多的python高级编程技巧、知识总结,第三章主要写实例化过程和类的创建过程中的技巧,第四章突出了pep8的作用,并给出各个地方的命名建议,第五章给出了一个具体在setuptools下打包项目的实例,第六章给出了在实际生产中部署python软件时候会用到的软件及注意事项。
Python高级编程 (速查笔记 第3、4、5、6章)
第三章 最佳语法实践——类级别以上
1. 子类化内置类型
将内置的 list 或者 valueerror等内置类型自行继承,并加上功能,在自己的工作流程中使用自己的类的子类,能更好的实现自己的目标。
2. 访问超类中的方法
super().xxx()
可以在类内部调用超类的方法, 还可以用super(实例.__class__,实例).xxx()
的方法在外部调用实例的超类的方法,单独一个参数的super函数被认为只传了第一个参数,可以调用其类方法(用@classmethod 装饰的)
- python2 版本的class创建时候要显性继承自object 否则不继承,super要显式添加参数,不能无参调用。
- Python的解析方法(多重继承情况下 方法或者属性的查找顺序)使用C3前是——继承表从左到右,深度优先{并非是越接近越容易继承},Python2中如果不显式继承自object的话使用的就是上面这种解析方法,现在Python3都是C3 就是越接近越先继承。C3算法实例解释
- 当时使用super时候要注意,是否会引起代码再次调用代码的母类方法,可以使用
.__mro__
属性查看继承关系,或者查看源代码查看相关逻辑 - 最佳实践是 a.避免多重继承, b.super用法在类的层级中保持一致,c.python2要显式继承自object d.调用
__mro__
检查父类继承关系。
3. 高级属性访问模式
使用__xx
的命名方式可以避免myclass.__xx
的方式调用相关属性货方法,但是并不是强制的,可以通过其他方式访问到该属性。实践中使用单下划线_的方式来命名属性或方法,来避免其他函数调用。
- 描述符(descriptor) 另一个类调用描述符类来管理他内部的属性的 调用 删除 设置方法。描述符类需要实现三个(中前两个)特殊方法
__set__(self,obj,type=None) __get__(self,obj,value) __delete__(self.obj)
同时有 getter 何setter的类称之为数据描述符类,否则叫非描述符类。
查找相关属性时候 实际上是调用了数据描述符的__getattribute__
在访问目标类的过程中先检查是否有相关描述符类,没有再转入查找__dict__
最后查找非描述符类
举例子 P77页的惰性初始化List 的方法(利用非数据描述符在调用dict后执行的特点)
- property型数据描述符 在类的相关属性上面加上
@property
修饰器,在setter上面用@属性名.setter
的方式来定义setter,可以达到文件描述符类的效果, -
__slots__
槽 当类用这个属性规定一个列表后,这个列表将代替平时类创建时候需要创建的__dict__
对象,节省空间,但不能使用猴子补丁、这类依赖__dict__
对象的特性,并且其实例对象将不能自行添加其他属性。(其子类不继承__slots__
方法,可以正常使用)
4. 元编程
- 装饰器 同第二章的装饰器,输入是一个函数 ,输出也是一个函数
- 类装饰器 与装饰器类似,输入一个类,输出一个类,可以改变类中的方法。
- 既修可以改类,又可以修改对象。
- 类的函数也是遵守描述符的对象(跟属性的调用方法相同,可以用非描述符方法来绑定一些操作)
- 类的 super方法在正确的参数下可以在类的外部使用
- 可以用于类的定义
因为使用装饰器修饰的类,在创建时候会被成为装饰器临时创建的子类的的实例 而不是原来类的实例,这样一些__name__ __doc__
会被改变。
通常使用MIXIN类作为这类需要使用类装饰器的替代,这种类不是用来实例化的,是用来做接口类让别人继承的。
- 复写类的
__new__()
方法
常用做缓存,单例模式,实例计数等需要在实例化(前)时候做的工作,注意如果调用其他类生成实例会跳过本类的init方法。 - 元类(Metaclass)
在Python中 实例与类与元类的关系是: 实例<<类<<type(metaclass)
- 类的实例化过程 实际上是调用
type(类名,基类列表,命名空间)(传入参数)
这个函数,或者说 类是type(类名,基类列表,命名空间)
的返回值。 - 定义元类可以改变 在调用
type(类名,基类列表,命名空间)
这个函数的行为重点包括以下四个函数:
-
__new__
创建类的时候的行为 (例如给类加通用属性和方法等) -
__prepare__
加入命名空间时候的行为 -
__init__
在创建类(元类的实例)的时候的行为,与类中的__init__
类似 -
__call__
在类被调用创建实例时候调用,跟类的__call__
类似
- python3 在定义metaclass时候 是用类的参数传入 (metaclass=我们的metaclass)来调用 2使用 with_metaclass(meta,base) 方式传入的。Python2没有 prepare方法
- 动态代码生成
- exec
- eval
- compile
- 小心使用 问题很可能会跑到except之外(传入代码逻辑导致外部其他代码逻辑崩溃,错误不在该段代码的try 范围内)
- 范例是在编译调用之前,例如在编译阶段加一些特征(用改写后的代码做debug 特殊配置等)
- 总结
本章介绍了 super的相关使用方法,介绍了数据描述符类 和@property的用途(实例的生成),其他部分介绍了元类和元编程 (类的生成部分)
第四章 选择好的名称
1 PEP 8 与命名最佳实践
遵守PEP8 是为了让项目走的更远,跟更多的人合作开发
2. 命名风格;
- 常量 大写 和下划线 用于常量,引用值,要求能代表其意义
- 变量 私有,局部 使用单下划线开头
- 函数和方法名 小写加下划线
- 特殊方法 双下划线 开头和结尾 别自己瞎写
- 参数 小写 和下划线开头小写
- property 小写和下划线
- 类 驼峰模式
- 模块 和包 小写
3. 命名指南
- 用has 和is 来做布尔元素的开头
- 用复数形式命名集合型变量
- 显式命名(名字能表意)
- 避免过于通用的名字 例如 object manager handle perform等词
- 避免使用保留字或者已有名称
4. 最佳实践
- 迭代构建参数 利用内部接口调用时候可以使用默认参数的方法兼容不同版本的具体被调用函数
- assert 不要滥用仅作为前提使用,不做测试,更优质的做法是TDD
- 小心使用魔法参数
*args **kwargs
args 用生成器代替, kwargs用显式参数附带默认值代替。
5. 类的命名
抽象用Abstract 或者 Base 开头,能看懂的名字,避免类和其属性或者函数有重复的地方。
6. 模块和包的名称
- 表意明确,不带下划线的小写
- 与协议相关 使用lib结尾
- 避免与标准类重名
- 可拆分
7. 辅助工具
- pylint 出一份详细的报告
- pep8
- flake8
第五章 编写一个包
1. 创建一个包
- 工具推荐
- pip 用来安装包
- virtualenv venv 用来创建隔离环境
- setuptool 构建源代码发行版(包含 distutils)
- wheel 构建发行版
- twine 上传到 Pypi
- 项目配置
- 根目录需要放一个 setup.py (distutils需要的元数据,可用setuptools的包来代替)
- setup.cfg 将值怼到这个配置文件里
- 跟setup.py 同目录MANIFEST.in 负责包含和排除文件
- 常用元数据
- description 简短描述语
- long_description 完整描述
- keywords 关键词列表
- author 作者
- author_email
- url 项目URL
- license
- packages 所有包的名称列表
- namespace_packages 命名空间包列表
- trove 分类器,用来给 classifier 添加各种分类(方便其他人查找到你的包)
- 常见模式
from setuptools import setup
setup(
name=“项目名称”,
version=“0.0.1”
…
install_requires={
‘django’,
‘flask’
}
)7.注意 /附言
1. 版本号放在 包下 空`__init__.py` 内部` __version__`属性内
2. readme文件 使用reStructuredText格式 可用其他格式转
3. 管理依赖 应该使用在setup函数中确定包的模式,如果使用requirements.txt的话使用 install_requires=reqs('requirements.txt')的方式引入依赖
- 自定义setup命令 在setup函数中 添加entry_points=""" [distutils.commands]
my_command=my.command.module.Class
“”"(P132) - 开发期间使用包
- 可用 setup.py install 和 pip install 包路径 的方式安装包(提前验证)
- 使用 pip uninstall 包名 来卸载包
- 使用 setup.py develop 或者 pip -e 来创建可编辑的包,(类似软连接)
2. 命名空间包
- 有啥用 可以在同一个包(命名空间内)放置多个独立的包
- 使用 A.B/A/B 与A.C/A/C 这两个包 同时开发 可以看做 同属于A的两个包 B,C (python3)
- 上述结构下 需要在A下面加一个 空的__init__.py包才可以当做这两个是一个包 (Python2)
3. 上传一个包
- 用 setup.py xxx upload模式可以上传 其中 xxx 表示 上传那些版本(发行还是源代码啥的)P138
- .pypirc 包含一些仓库的信息,包括上传地址 用户名密码等等 密码可以留空 会提示
- 源码包 与 构建包
- setup.py sdist 构建一个dist文件夹 文件夹中是一个或者多个.tar压缩包
- bdist 二进制发行版 和 wheel 优于bdist的二进制发行,linux不可用
4. 独立可执行文件(单独打包)
1. 为啥用这个方式 Python版本不通用,依赖于预编译的Cpython 有图形界面的 多语言复合的 游戏
2. pyinstaller cx_Freeze py2EXE py2app
3. 抗反编译 p151 主要是使用中间产物AST
5. 总结
主要是介绍打包的需要的一些工具和发行版本的却别,可执行文件等,下一章的预备知识。
第六章. 部署代码
1. 十二要素应用
- 代码库(codebase) 版本控制追踪一份代码库,多份部署
- 依赖 显式声明,隔离依赖关系
- 配置 在环境中存储配置
- 后端服务 将后端服务作为附加资源
- 构建 发布 运行 严格分离构建和运行阶段
- 进程 以一个或者个多个无状态进程运行应用
- 端口绑定 通过端口绑定提供服务。
- 并发 功过进程模型进行扩展
- 易处理 快速启动和优雅终止,最大化鲁棒性
- 开发环境和生产环境 尽可能保持 开发,预发布,生产环境相同
- 日志 把日志当做事件流
- 管理进程 讲后台管理任务当做一次性进程运行
2. fabric(2)自动化部署
- fabric2 已经发布 支持 Python 3.4+ 大致可以看做这个工具是一个通过SSH跟远端主机交互的API接口
用这个接口可以完成一些复杂的判断 安装以及很多其他需要自动化处理的安装步骤 在 需要创建一个 fabfile.py
然后在其内部维护需要的代码仓地址,自动化逻辑,等 最后使用 fab --list 在fabric包位置运行 得到相关命令并运行。p157
3.自有包索引或者索引镜像
- pip Pypi自带CDN 可以用 bandersnatch工具自己下载pypi镜像 比较大 数百G 不可以自己上传
- 可以使用devpi替代 bandersnatch 惰性加载定期更新 可以加自定义包
- django自动打包项目延时 p166
4.常见约定与实践
- 使用文件系统的时候 尽量在基础设施中 项目组织中 保持一致
- 隔离 为每个版本做自己的venv 方便回滚
- 进程管理 使用 Circus配置 配置好相关的 circus.ini后 就可以使用 circusctl xxx start 模式来开关相应的Python应用了。
- 不要使用root权限 应该在用户空间运行应用代码
- 使用HTTP反向代理
- 优雅的退出与重载,需要设计退出,并且跟系统底层有一定了解
5. 代码检测与监控
- 使用Sentry Raven来分析错误。
- 使用Munin来监控应用与指标
- 日志处理
- 流式处理 同 1.
- 日志分析工具 ELK系统
6. 小结
代码部署很广泛,涉及很多方面,建议自动化处理部署及监控自己的应用。