[
  {
    "path": ".gitignore",
    "content": "﻿.idea\n.vscode\n.github\nimg/*.html\nnotebook\nvenv\n"
  },
  {
    "path": "README.md",
    "content": "\n<div align=\"center\">\n<img src=\"https://img.shields.io/badge/-Python-brightgreen\">\n<img src=\"https://img.shields.io/badge/-%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90-yellowgreen\">\n<img src=\"https://img.shields.io/badge/-%E7%AE%97%E6%B3%95-yellow\">\n<img src=\"https://img.shields.io/badge/-%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0-lightgrey\">\n<a href=\"https://static01.imgkr.com/temp/c6e10a16c4764dcdb32587760f6769ec.png\" width=\"28%\"><img src=\"https://img.shields.io/badge/%E5%85%AC%E4%BC%97%E5%8F%B7-Python%E5%B0%8F%E4%BE%8B%E5%AD%90-orange\"></a>\n</div>\n<br>\n\n<!-- <div align=\"center\">\n<img src=\"https://static01.imgkr.com/temp/f379139a2c5d463799c35c1aa68911d7.png\" width=\"18%\"/>\n</div> -->\n</div>\n\n## 介绍\n\n告别枯燥，告别枯燥，致力于打造 Python 经典小例子、小案例。 \n\n## License\n\n允许按照要求转载，但禁止用于任何商用目的。如果转载本库小例子、小案例，请备注下方链接：\n\n[Python小例子所有汇总](https://ai-jupyter.com/python-small-examples/)\n\n### 更多教程\n\n[AI消息](https://ai-jupyter.com/)\n\n[AI新闻报道](https://ai-jupyter.com/ai-news-all/)\n\n[AI大模型](https://ai-jupyter.com/ai-llm/)\n\n[AI工具集](https://ai-jupyter.com/ai-chatgpt/)\n\n[ChatGPT4o免费使用六种方法](https://ai-jupyter.com/ai-chatgpt/)\n\n[Python教程](https://ai-jupyter.com/python-packages/)\n\n[数据分析教程](https://ai-jupyter.com/numpy-intro/)\n\n[算法教程](https://ai-jupyter.com/algorithm-basic/)\n\n[AI教程](https://ai-jupyter.com/statistics/)\n\n[Git教程](https://ai-jupyter.com/git/)\n\n[程序员](https://ai-jupyter.com/others/)\n\n[资料下载](https://ai-jupyter.com/python-20/)\n\n\n## Python 小例子\n\n### 基本操作\n\n| 小例子 | 链接                    | 标签              | 版本          | 难度 |\n| ---- | ---------------------------------- | ---- | ---- | ---- |\n|1   | [常见算术运算](md/198.md)|\t运算  |\tv1|\t⭐⭐ |\n| 2    | [实现 relu](md/1.md) | max   | V4.0        | ⭐️⭐️ |\n| 3    | [进制转化](md/2.md)                | bin,oct,hex | V4.0            |  ⭐️⭐️|\n| 4    | [整数和ASCII互转](md/3.md)         | chr,ord | V1.0     | ⭐️⭐️ |\n| 5    | [元素都为真检查](md/4.md)          | all   | V2.0      | ⭐️⭐️⭐️ |\n| 6    | [至少一个为真检查](md/5.md)        | any | V2.0    | ⭐️⭐️⭐️ |\n| 7    | [判断是真是假](md/6.md)            | bool        | V2.0        | ⭐️⭐️⭐️ |\n| 8    | [创建复数](md/7.md)                | complex         | V1.0            | ⭐️⭐️⭐️ |\n| 9    | [取商和余数](md/8.md)              | divmod        | V1.0          | ⭐️⭐️ |\n| 10    | [转为浮点类型](md/9.md)            | float       | V1.0        | ⭐️⭐️ |\n| 11   | [转为整型](md/10.md)               | int            | V1.0           | ⭐️ |\n| 12   | [次幂](md/11.md)                   | pow                | V1.0               | ⭐️ |\n| 13   | [四舍五入](md/12.md)               | round          | V1.0           | ⭐️ |\n| 14   | [链式比较](md/13.md)               | compare       | V1.0           | ⭐️⭐️ |\n| 15   | [字符串转字节](md/14.md)           | bytes,utf-8 | V1.0       | ⭐️⭐️ |\n| 16   | [任意对象转为字符串](md/15.md)     | str  | V1.0 | ⭐️⭐️ |\n| 17   | [执行字符串表示的代码](md/16.md)   | compile | V1.0 | ⭐️⭐️⭐️ |\n| 18   | [计算表达式](md/17.md)             | eval         | V1.0         | ⭐️⭐️⭐️⭐️ |\n| 19   | [字符串格式化](md/18.md)           | format     | V1.0       | ⭐️⭐️⭐️⭐️ |\n| 20   | [交换两元素](md/23.md)             | pack,unpack | V1.0         | ⭐️⭐️ |\n| 21   | [转为字典](md/29.md)               | dict           | V1.0           | ⭐️⭐️ |\n| 22   | [冻结集合](md/30.md)               | frozenset | V1.0           | ⭐️⭐️ |\n| 23   | [转为集合类型](md/31.md)           | set        | V1.0       | ⭐️⭐️ |\n| 24   | [转元组](md/32.md)                 | tuple            | V1.0             | ⭐️⭐️ |\n| 25   | [查看变量所占字节数](md/48.md)  | getsizeof | V1.0 | ⭐️⭐️⭐️ |\n| 26 | [含单个元素的元组](md/154.md) | tuple | V1.0 | ⭐️⭐ |\n| 27 | [列表删除之坑](md/159.md) | list | V1.0 | ⭐️⭐ |\n| 28 | [列表快速复制之坑](md/160.md) | list  | V1.0 | ⭐️⭐⭐ |\n| 29 | [发现列表前3个最大或最小数](md/195.md) | list heapq | v1.0 | ⭐️⭐⭐⭐ |\n| 30 | [字符串驻留](md/161.md) | str  | V1.0 | ⭐️⭐⭐⭐⭐ |\n| 31 | [创建空集合错误](md/166.md) | set  | V1.0 | ⭐️⭐ |\n| 32 | [充分认识for](md/164.md) | for  | V1.0 | ⭐️⭐⭐ |\n| 33 | [认识执行时机](md/165.md) | generator  | V1.0 | ⭐️⭐⭐⭐⭐ |\n\n\n### 函数和模块常见用法\n\n| 小例子 | 链接                    | 标签              | 版本          | 难度 |\n| ---- | ---------------------------------- | ---- | ---- | ---- |\n| 1   | [操作函数对象](md/24.md)           | operator   | V2.0       | ⭐️⭐️⭐️⭐️ |\n| 2   | [创建range序列](md/55.md) | range | V1.0 | ⭐️⭐️ |\n| 3   | [生成逆序序列](md/25.md)           | range | V1.0       | ⭐️⭐️ |\n| 4   | [拿来就用的排序函数](md/19.md)     | sorted | V1.0 | ⭐️⭐️⭐️ |\n| 5   | [求和函数](md/20.md)               | sum            | V1.0           | ⭐️⭐️ |\n| 6   | [函数的五类参数使用例子](md/26.md) | variable parameter | V2.0 | ⭐️⭐️⭐️⭐️ |\n| 7   | [使用slice对象](md/27.md)          | slice     | V2.0      | ⭐️⭐️⭐️⭐️⭐️ |\n| 8   | [lambda 函数](md/28.md)  | lambda | V3.0 | ⭐️⭐️⭐️⭐️ |\n| 9   | [枚举对象](md/47.md)       | enumerate | V1.0   | ⭐️⭐️⭐️ |\n| 10   | [过滤器filter](md/49.md)  | filter | V1.5 | ⭐️⭐️⭐️ |\n| 11   | [返回对象哈希值](md/50.md)    | hash | V1.0 | ⭐️⭐️ |\n| 12   | [带名字的元组](md/79.md) | namedtuple | V1.0 | ⭐️⭐️⭐️ |\n| 13   | [一行代码实现列表反转](md/70.md) | reverse | V1.0 | ⭐️⭐️ |\n| 14   | [反转字符串的两个方法](md/86.md) | reversed | V1.0 | ⭐️⭐️ |\n| 15   | [join 串联字符串](md/87.md) | join | V1.0 | ⭐️⭐️ |\n| 16   | [字符串字节长度](md/88.md) | encode | V1.0 | ⭐️⭐️ |\n| 17 | [groupby单字段分组](md/129.md) | itertools, groupby,lambda | V1.0 | ⭐️⭐️⭐️ |\n| 18 | [groupby多字段分组](md/130.md) | itemgetter,itertools,groupby | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 19 | [itemgetter和key函数](md/131.md) | operator,itemgetter,itertools | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |\n| 20 | [sum函数计算和聚合同时做](md/132.md) | sum,generator | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |\n| 21 | [默认参数设为空](md/155.md) | function | V1.0 | ⭐️⭐⭐ |\n| 22 | [各种参数使用之坑](md/158.md) | function paremeter | V1.0 | ⭐️⭐⭐ |\n| 23 | [lambda自由参数之坑](md/157.md) | lambda | V1.0 | ⭐️⭐⭐ |\n| 24 | [使用堆升序列表](md/196.md) | sort heapq | v1.0 | ⭐️⭐⭐⭐ |\n\n\n### 面向对象\n| 小例子 | 链接                    | 标签              | 版本          | 难度 |\n| ---- | ---------------------------------- | ---- | ---- | ---- |\n| 1   | [所有对象之根](md/43.md)           | object     | V1.0       | ⭐️ |\n| 2   | [对象是否可调用](md/33.md)         | callable | V2.5   | ⭐️⭐️⭐️⭐️ |\n| 3   | [ascii 展示对象](md/34.md)         | `__repr__` | V2.5     | ⭐️⭐️⭐️ |\n| 4   | [类方法](md/35.md)                 | classmethod      | V1.5             | ⭐️⭐️⭐️ |\n| 5   | [动态删除属性](md/36.md)           | delattr,hasattr | V1.5       | ⭐️⭐️ |\n| 6   | [一键查看对象所有方法](md/37.md)   | dir | V1.5 | ⭐️⭐️ |\n| 7   | [动态获取对象属性](md/38.md)       | getattr | V1.5   | ⭐️⭐️ |\n| 8   | [对象是否有某个属性](md/39.md)     | hasattr | V1.5 | ⭐️⭐️⭐️ |\n| 9   | [对象门牌号](md/40.md)             | id           | V1.0         | ⭐️ |\n| 10   | [实例和对象关系判断](md/41.md)    | isinstance   | V1.5         | ⭐️⭐️⭐️ |\n| 11   | [issubclass父子关系鉴定](md/42.md) | issubclass | V1.5 | ⭐️⭐️⭐️ |\n| 12   | [创建属性的两种方法](md/44.md)     | property | V2.5 | ⭐️⭐️⭐️⭐️⭐️ |\n| 13   | [查看对象类型](md/45.md)           | type      | V1.0       | ⭐️ |\n| 14   | [元类使用介绍](md/46.md)     | type,`__class__` | V2.0 | ⭐️⭐️⭐️⭐️⭐️ |\n| 15 | [相同值的不可变对象](md/162.md) | mutable  | V1.0 | ⭐️⭐⭐ |\n| 16 | [对象销毁顺序](md/163.md) | OOP del   | V1.0 | ⭐️⭐⭐⭐ |\n| 17 | [子类继承父类的静态方法吗？](md/171.md) | staticmethod | V1.0 | ⭐️⭐⭐ |\n\n\n\n### 正则\n| 小例子 | 链接                    | 标签              | 版本          | 难度 |\n| ---- | ---------------------------------- | ---- | ---- | ---- |\n| 1   | [正则中字符 `r`作用](md/89.md) | re,r | V3.0 | ⭐️⭐️⭐️ |\n| 2   | [正则原子操作](md/90.md) | re | V3.0 | ⭐️⭐️⭐️ |\n| 3   | [正则中的转义](md/91.md) | re,\\ | V3.0 | ⭐️⭐️⭐️ |\n| 4   | [正则最普通查找](md/92.md) | re,findall | V3.0 | ⭐️⭐️⭐️ |\n| 5   | [使用通用字符查找](md/93.md) | re,\\s,\\w,\\d | V3.0 | ⭐️⭐️⭐️ |\n| 6   | [使用元字符查找](md/94.md) | re,+,* | V3.0 | ⭐️⭐️⭐️ |\n| 7   | [捕获子串](md/95.md) | () | V3.0 | ⭐️⭐️⭐️⭐️ |\n| 8   | [贪心捕获和非贪心捕获](md/96.md) | re | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 9   | [使用正则做密码安全检查](md/97.md) | re | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |\n| 10   | [爬取百度首页标题](md/98.md) | re | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 11   | [批量转化为驼峰格式(Camel)](md/99.md) | re | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |\n| 12   | [使用正则判断是否为正浮点数](md/102.md) | str,re,float | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |\n| 13 | [使用正则提取正整数和大于0的浮点数](md/197.md) | re findall | v2 | ⭐️⭐⭐⭐ |\n\n### 装饰器迭代器生成器\n| 小例子 | 链接                    | 标签              | 版本          | 难度 |\n| ---- | ---------------------------------- | ---- | ---- | ---- |\n| 1 | [通俗理解装饰器](md/138.md) | decorator | V1.0 | ⭐️⭐️⭐️ |\n| 2 | [测试函数运行时间的装饰器](md/136.md) | decorator | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 3 | [统计异常次数装饰器](md/137.md) | decorator,nonlocal | V1.5 | ⭐️⭐️⭐️⭐️ |\n| 4 | [定制递减迭代器](md/139.md) | Iterator | V3.0 | ⭐️⭐️⭐️⭐️ |\n| 5   | [创建迭代器](md/53.md)      | iter,`__iter__` | V1.5  | ⭐️⭐️⭐️ |\n| 6   | [反向迭代器reversed](md/56.md) | reversed | V1.0 | ⭐️⭐️ |\n| 7   | [zip迭代器](md/57.md)     | zip  | V1.5 | ⭐️⭐️⭐️ |\n| 8 | [list分组(生成器版)](md/134.md) | yield,generator | V1.0 | ⭐️⭐️⭐️ |\n| 9 | [列表全展开(生成器版)](md/135.md) | list,yield,generator | V1.0 | ⭐️⭐️⭐️ |\n| 10   | [chain串联小容器为大容器](md/84.md) | itertools,chain | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |\n| 11   | [product 使用案例](md/85.md) | product | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |\n| 12 | [斐波那契数列前n项](md/126.md) | yield,range | V1.0 | ⭐️⭐️⭐️ |\n\n\n### 绘图\n| 小例子 | 链接                    | 标签              | 版本          | 难度 |\n| ---- | ---------------------------------- | ---- | ---- | ---- |\n| 1 | [turtle绘制奥运五环图](md/140.md) | turtle | V1.0 | ⭐️⭐️⭐️ |\n| 2 | [turtle绘制漫天雪花](md/141.md) | turtle | V1.0 | ⭐️⭐️⭐️ |\n| 3 | [Python词云图](md/142.md) | WordCloud | V1.0 | ⭐️⭐️⭐ |\n| 4 | [Plotly柱状图和折线图](md/143.md) | plotly | V1.0 | ⭐️⭐ |\n| 5 | [seaborn热力图](md/144.md) | seaborn | V1.0 | ⭐️⭐ |\n| 6 | [Pyecharts仪表盘](md/145.md) | pyecharts | V1.0 | ⭐️⭐ |\n| 7 | [Pyecharts漏斗图](md/146.md) | pyecharts | V1.0 | ⭐️⭐ |\n| 8 | [Pyecharts水球图](md/147.md) | pyecharts | V1.0 | ⭐️⭐ |\n| 9 | [Pyecharts饼图](md/148.md) | pyecharts | V1.0 | ⭐️⭐ |\n| 10 | [Pyecharts极坐标图](md/149.md) | pyecharts | V1.0 | ⭐️⭐ |\n| 11 | [Pyecharts词云图](md/150.md) | pyecharts | V1.0 | ⭐️⭐ |\n| 12 | [Pyecharts热力图](md/151.md) | pyecharts | V1.0 | ⭐️⭐ |\n| 13 | [matplotlib绘制动图](md/152.md) | matplotlib | V1.0 | ⭐️⭐ |\n| 14 | [seaborn pairplot图](md/153.md) | seaborn | V1.0 | ⭐️⭐⭐⭐ |\n| 15 | [pyecharts传入Numpy数据绘图失败](md/167.md) | numpy pyecharts  | V1.0 | ⭐️⭐⭐ |\n| 16 | [图像处理包pillow](md/169.md) | pillow  | V1.0 | ⭐️⭐⭐ |\n\n### 数据分析\n| 小例子 | 链接                    | 标签              | 版本          | 难度 |\n| ---- | ---------------------------------- | ---- | ---- | ---- |\n| 1 | [数据分析神器：deepnote](./md/177.md) | deepnote | v1.0 | ⭐️⭐⭐ |\n| 2 | [NumPy 的pad填充方法](md/172.md) | NumPy pad | V1.0 | ⭐️⭐⭐⭐ |\n| 3 | [创建下对角线为1、2、3、4的对角矩阵](md/173.md) | NumPy diag | V1.0 | ⭐️⭐⭐ |\n| 4 | [cut 数据分箱](md/174.md) | Pandas cut | v1.0 | ⭐️⭐⭐ |\n| 5 | [丢弃空值和填充空值](./md/175.md) | Pandas dropna fillna | v1.0 | ⭐️⭐⭐ |\n| 6 | [apply 方法去掉特殊字符](./md/178.md) | pandas apply | v1.0 | ⭐️⭐⭐ |\n| 7 | [使用map对列做特征工程](./md/179.md) | pandas map | v1.0 | ⭐️⭐⭐ |\n| 8 | [category列转数值](./md/180.md) | pandas category | v1.0 | ⭐️⭐⭐ |\n| 9 | [rank排名](./md/181.md) | pandas rank | v1.0 | ⭐️⭐⭐|\n| 10 | [完成数据下采样，调整步长由小时为天](./md/182.md) | pandas resample | v1.0 | ⭐️⭐⭐ |\n| 11 | [如何用 Pandas 快速生成时间序列数据](./md/183.md) | pandas util | v1.0 | ⭐️⭐⭐ |\n| 12 | [如何快速找出 DataFrame 所有列 null 值个数](./md/184.md) | pandas isnull sum | v1.0 | ⭐️⭐⭐ |\n| 13 | [重新排序 DataFrame 的列](./md/185.md) | pandas dataframe | v1.0 | ⭐️⭐⭐ |\n| 14 | [使用 count 统计词条 出现次数](./md/186.md) | pandas count | v1.0 | ⭐️⭐⭐ |\n| 15 | [split 求时分(HH:mm)的分钟差](./md/187.md) | pandas split | v1.0 | ⭐️⭐⭐ |\n| 16 | [melt透视数据小技巧](./md/188.md) | pandas melt | v1.0 | ⭐️⭐⭐ |\n| 17 | [pivot 透视小技巧](./md/189.md) | pandas melt | v1.0 | ⭐️⭐⭐ |\n| 18 | [p随机读取文件的K行，生成N个](./md/190.md) | pandas sample | v1.0 | ⭐️⭐⭐ |\n| 19 | [格式化Pandas的时间列](md/191.md) | pandas apply | v1.0 | ⭐️⭐⭐⭐ |\n\n### 其他常用\n| 小例子 | 链接                    | 标签              | 版本          | 难度 |\n| ---- | ---------------------------------- | ---- | ---- | ---- |\n| 1   | [help 一键帮助](md/51.md)  | help | V1.0 | ⭐️ |\n| 2   | [获取用户输入](md/52.md)     | input | V1.0 | ⭐️ |\n| 3   | [文件读写和mode 取值表](md/54.md) | open,read,write,with,mode | V2.0 | ⭐️⭐️⭐️ |\n| 4   | [operator使用举例](md/58.md) | operator | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 5   | [传输json对象](md/59.md)  | json | V2.0 | ⭐️⭐️⭐️⭐️⭐️ |\n| 6   | [获取文件后缀名](md/103.md) | os,splitext | V1.0 | ⭐️⭐️ |\n| 7   | [获取路径中的文件名](md/104.md) | os,split | V1.0 | ⭐️⭐️ |\n| 8   | [批量修改文件后缀](md/105.md) | argparse,listdir | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 9   | [xls批量转换成xlsx](md/106.md) | os,listdir,splitext | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 10   | [获取指定后缀名的文件](md/107.md) | os,listdir,splitext | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 11   | [批量压缩文件](md/108.md) | zipfile | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 12   | [32位加密](md/109.md) | hashlib | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 13   | [年的日历图](md/110.md) | calendar | V1.0 | ⭐️⭐️ |\n| 14   | [判断是否为闰年](md/111.md) | calendar | V1.0 | ⭐️⭐️⭐️ |\n| 15   | [判断月有几天](md/112.md) | calendar,datetime | V1.0 | ⭐️⭐️⭐️ |\n| 16   | [月的第一天](md/113.md) | datetime | V1.0 | ⭐️⭐️ |\n| 17 | [月的最后一天](md/114.md) | calendar,datetime | V1.0 | ⭐️⭐️ |\n| 18 | [获取当前时间](md/115.md) | time,datetime | V1.0 | ⭐️⭐️ |\n| 19 | [字符时间转时间](md/116.md) | time,datetime | V1.0 | ⭐️⭐️ |\n| 20 | [时间转字符时间](md/117.md) | time,datetime | V1.0 | ⭐️⭐️ |\n| 21 | [获得某天后的1~n天](md/133.md) | Calendar,monthrange | V4.0 | ⭐️⭐️⭐️ |\n| 22 | [默认启动主线程](md/118.md) | threading | V1.0 | ⭐️⭐️ |\n| 23 | [创建线程](md/119.md) | threading | V1.0 | ⭐️⭐️ |\n| 24 | [交替获得CPU时间片](md/120.md) | threading | V1.0 | ⭐️⭐️⭐️ |\n| 25 | [多线程抢夺同一个变量](md/121.md) | threading | V1.0 | ⭐️⭐️⭐️ |\n| 26 | [多线程变量竞争引起的问题](md/122.md) | threading | V1.0 | ⭐️⭐️⭐️ |\n| 27 | [多线程锁](md/123.md) | threading,lock | V1.0 | ⭐️⭐️⭐️ |\n| 28 | [时间转数组及常用格式](md/124.md) | time,datetime,format | V1.0 | ⭐️⭐️⭐️ |\n| 29   | [nonlocal用于内嵌函数中](md/21.md) | nonlocal | V2.0 | ⭐️⭐️⭐️⭐️⭐️ |\n| 30   | [global 声明全局变量](md/22.md)    | global | V2.0 | ⭐️⭐️⭐️⭐️⭐️ |\n| 31 | [共享变量未绑定之坑](md/156.md) | global | V1.0 | ⭐️⭐⭐ |\n| 32 | [优化代码异常输出包](md/168.md) | debugger  | V1.0 | ⭐️⭐⭐ |\n| 33 | [一行代码找到编码](md/170.md) | chardet  | V1.0 | ⭐️⭐⭐ |\n| 34 | [创建SQLite连接](md/192.md) | SQLite | v1.0 | ⭐️⭐⭐⭐ |\n| 35 | [json对象转python对象](md/193.md) | python json | v1.0 | ⭐️⭐⭐⭐ |\n| 36 | [python对象转json对象](md/194.md) | python json | v1.0 | ⭐️⭐⭐⭐ |\n| 37 | [一行代码让 pip 安装加速 100 倍](md/176.md) | pip install | v1.0 | ⭐️⭐⭐ |\n\n\n### 工作常用案例\n| 小例子 | 链接                    | 标签              | 版本          | 难度 |\n| ---- | ---------------------------------- | ---- | ---- | ---- |\n| 1   | [不用else和if实现计算器](md/60.md) | operator | V1.0 | ⭐️⭐️⭐️ |\n| 2   | [去最求平均](md/61.md)      | list,sort,round | V1.0  | ⭐️⭐️⭐️⭐️ |\n| 3   | [打印99乘法表](md/62.md)    | for,range,format | V1.0 | ⭐️⭐️⭐️ |\n| 4   | [递归版flatten函数](md/63.md) | recursion,list,isinstance | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 5   | [列表等分为n份](md/64.md)  | list,ceil | V1.0 | ⭐️⭐️⭐️ |\n| 6   | [压缩列表](md/65.md)       | list,filter | V1.0   | ⭐️⭐️⭐️⭐️ |\n| 7   | [求更长的列表](md/66.md)     | max,lambda | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |\n| 8   | [求列表众数](md/67.md)     | max,lambda,count | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 9   | [所有多个列表的最大值](md/68.md) | max,lambda | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 10   | [列表检查重复](md/69.md)     | set  | V1.0 | ⭐️⭐️⭐️ |\n| 11   | [浮点数等差数列](md/71.md)    | range,float | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 12   | [按条件分组](md/72.md)      | lambda | V1.0  | ⭐️⭐️⭐️⭐️ |\n| 13   | [map实现向量运算](md/73.md)  | map,lambda | V1.0 | ⭐️⭐️⭐️ |\n| 14   | [值最大的字典](md/74.md)     | max,lambda | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 15   | [合并两个字典](md/75.md)     | **   | V1.0 | ⭐️⭐️⭐️ |\n| 16   | [Topn 字典](md/76.md)    | heapq,nlargest | V1.0 | ⭐️⭐️⭐️ |\n| 17   | [判断是否为异位词](md/77.md) | collections,Counter | V1.0 | ⭐️⭐️⭐️ |\n| 18   | [逻辑上合并字典](md/78.md) | ChainMap | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |\n| 19   | [sample 样本抽样](md/80.md) | random,sample | V1.0 | ⭐️⭐️⭐️ |\n| 20   | [重洗数据集](md/81.md) | shuffle | V1.0 | ⭐️⭐️⭐️ |\n| 21   | [10个均匀分布的坐标点](md/82.md) | random,uniform | V1.0 | ⭐️⭐️⭐️ |\n| 22   | [10个高斯分布的坐标点](md/83.md) | random,gauss | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 23   | [是否互为排序词](md/100.md) | collections,defaultdict | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 24   | [str1是否由str2旋转而来](md/101.md) | str | V1.0 | ⭐️⭐️⭐️ |\n| 25 | [寻找第n次出现位置](md/125.md) | enumerator | V1.0 | ⭐️⭐️⭐️ |\n| 26 | [找出所有重复元素](md/127.md) | calendar,datetime | V1.0 | ⭐️⭐️⭐️⭐️ |\n| 27 | [联合统计次数](md/128.md) | Counter | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |\n| 28 | [求两点球面距离](md/199.md) | math asin | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |\n| 29 | [获取文件编码](md/200.md) | chardet | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |\n| 30 | [格式化json串](md/201.md) | json | V1.0 | ⭐️⭐️⭐️⭐️⭐️ |\n\n\n\n\n"
  },
  {
    "path": "dev/python-dev.md",
    "content": "### Python 实战\n\n\n#### 221 自动群发邮件\n\nPython自动群发邮件\n\n```python\nimport smtplib\nfrom email import (header)\nfrom email.mime import (text, application, multipart)\nimport time\n\ndef sender_mail():\n    smt_p = smtplib.SMTP()\n    smt_p.connect(host='smtp.qq.com', port=25)\n    sender, password = '113097485@qq.com', \"**************\"\n    smt_p.login(sender, password)\n    receiver_addresses, count_num = [\n        'guozhennianhua@163.com', 'xiaoxiazi99@163.com'], 1\n    for email_address in receiver_addresses:\n        try:\n            msg = multipart.MIMEMultipart()\n            msg['From'] = \"zhenguo\"\n            msg['To'] = email_address\n            msg['subject'] = header.Header('这是邮件主题通知', 'utf-8')\n            msg.attach(text.MIMEText(\n                '这是一封测试邮件，请勿回复本邮件~', 'plain', 'utf-8'))\n            smt_p.sendmail(sender, email_address, msg.as_string())\n            time.sleep(10)\n            print('第%d次发送给%s' % (count_num, email_address))\n            count_num = count_num + 1\n        except Exception as e:\n            print('第%d次给%s发送邮件异常' % (count_num, email_address))\n            continue\n    smt_p.quit()\n\nsender_mail()\n```\n\n\n\n注意：\n发送邮箱是qq邮箱，所以要在qq邮箱中设置开启SMTP服务，设置完成时会生成一个授权码，将这个授权码赋值给文中的`password`变量\n\n#### 222 二分搜索\n\n二分搜索是程序员必备的算法，无论什么场合，都要非常熟练地写出来。\n\n小例子描述：\n在**有序数组**`arr`中，指定区间`[left,right]`范围内，查找元素`x`\n如果不存在，返回`-1`\n\n二分搜索`binarySearch`实现的主逻辑\n\n```python\ndef binarySearch(arr, left, right, x):\n    while left <= right:\n\n        mid = int(left + (right - left) / 2); # 找到中间位置。求中点写成(left+right)/2更容易溢出，所以不建议这样写\n\n        # 检查x是否出现在位置mid\n        if arr[mid] == x:\n            print('found %d 在索引位置%d 处' %(x,mid))\n            return mid\n\n            # 假如x更大，则不可能出现在左半部分\n        elif arr[mid] < x:\n            left = mid + 1 #搜索区间变为[mid+1,right]\n            print('区间缩小为[%d,%d]' %(mid+1,right))\n\n        # 同理，假如x更小，则不可能出现在右半部分\n        elif x<arr[mid]:\n            right = mid - 1 #搜索区间变为[left,mid-1]\n            print('区间缩小为[%d,%d]' %(left,mid-1))\n\n    # 假如搜索到这里，表明x未出现在[left,right]中\n    return -1\n```\n\n在`Ipython`交互界面中，调用`binarySearch`的小Demo:\n\n```python\nIn [8]: binarySearch([4,5,6,7,10,20,100],0,6,5)\n区间缩小为[0,2]\nfound 5 at 1\nOut[8]: 1\n\nIn [9]: binarySearch([4,5,6,7,10,20,100],0,6,4)\n区间缩小为[0,2]\n区间缩小为[0,0]\nfound 4 at 0\nOut[9]: 0\n\nIn [10]: binarySearch([4,5,6,7,10,20,100],0,6,20)\n区间缩小为[4,6]\nfound 20 at 5\nOut[10]: 5\n\nIn [11]: binarySearch([4,5,6,7,10,20,100],0,6,100)\n区间缩小为[4,6]\n区间缩小为[6,6]\nfound 100 at 6\nOut[11]: 6\n```\n\n#### 223 爬取天气数据并解析温度值\n\n爬取天气数据并解析温度值\n\n素材来自朋友袁绍，感谢！\n\n爬取的html 结构\n\n<img src=\"./img/1.png\" width=\"50%\"/>\n\n```python\nimport requests\nfrom lxml import etree\nimport pandas as pd\nimport re\n\nurl = 'http://www.weather.com.cn/weather1d/101010100.shtml#input'\nwith requests.get(url) as res:\n    content = res.content\n    html = etree.HTML(content)\n```\n\n\n\n通过lxml模块提取值\n\nlxml比beautifulsoup解析在某些场合更高效\n\n```python\nlocation = html.xpath('//*[@id=\"around\"]//a[@target=\"_blank\"]/span/text()')\ntemperature = html.xpath('//*[@id=\"around\"]/div/ul/li/a/i/text()')\n```\n\n结果：\n\n```python\n['香河', '涿州', '唐山', '沧州', '天津', '廊坊', '太原', '石家庄', '涿鹿', '张家口', '保定', '三河', '北京孔庙', '北京国子监', '中国地质博物馆', '月坛公\n园', '明城墙遗址公园', '北京市规划展览馆', '什刹海', '南锣鼓巷', '天坛公园', '北海公园', '景山公园', '北京海洋馆']\n\n['11/-5°C', '14/-5°C', '12/-6°C', '12/-5°C', '11/-1°C', '11/-5°C', '8/-7°C', '13/-2°C', '8/-6°C', '5/-9°C', '14/-6°C', '11/-4°C', '13/-3°C'\n, '13/-3°C', '12/-3°C', '12/-3°C', '13/-3°C', '12/-2°C', '12/-3°C', '13/-3°C', '12/-2°C', '12/-2°C', '12/-2°C', '12/-3°C']\n```\n\n\n构造DataFrame对象\n\n```python\ndf = pd.DataFrame({'location':location, 'temperature':temperature})\nprint('温度列')\nprint(df['temperature'])\n```\n\n正则解析温度值\n\n```python\ndf['high'] = df['temperature'].apply(lambda x: int(re.match('(-?[0-9]*?)/-?[0-9]*?°C', x).group(1) ) )\ndf['low'] = df['temperature'].apply(lambda x: int(re.match('-?[0-9]*?/(-?[0-9]*?)°C', x).group(1) ) )\nprint(df)\n```\n\n详细说明子字符创捕获\n\n除了简单地判断是否匹配之外，正则表达式还有提取子串的强大功能。用`()`表示的就是要提取的分组（group）。比如：`^(\\d{3})-(\\d{3,8})$`分别定义了两个组，可以直接从匹配的字符串中提取出区号和本地号码\n\n```python\nm = re.match(r'^(\\d{3})-(\\d{3,8})$', '010-12345')\nprint(m.group(0))\nprint(m.group(1))\nprint(m.group(2))\n\n# 010-12345\n# 010\n# 12345\n```\n\n如果正则表达式中定义了组，就可以在`Match`对象上用`group()`方法提取出子串来。\n\n注意到`group(0)`永远是原始字符串，`group(1)`、`group(2)`……表示第1、2、……个子串。\n\n\n最终结果\n\n```kepython\nName: temperature, dtype: object\n    location temperature  high  low\n0         香河     11/-5°C    11   -5\n1         涿州     14/-5°C    14   -5\n2         唐山     12/-6°C    12   -6\n3         沧州     12/-5°C    12   -5\n4         天津     11/-1°C    11   -1\n5         廊坊     11/-5°C    11   -5\n6         太原      8/-7°C     8   -7\n7        石家庄     13/-2°C    13   -2\n8         涿鹿      8/-6°C     8   -6\n9        张家口      5/-9°C     5   -9\n10        保定     14/-6°C    14   -6\n11        三河     11/-4°C    11   -4\n12      北京孔庙     13/-3°C    13   -3\n13     北京国子监     13/-3°C    13   -3\n14   中国地质博物馆     12/-3°C    12   -3\n15      月坛公园     12/-3°C    12   -3\n16   明城墙遗址公园     13/-3°C    13   -3\n17  北京市规划展览馆     12/-2°C    12   -2\n18       什刹海     12/-3°C    12   -3\n19      南锣鼓巷     13/-3°C    13   -3\n20      天坛公园     12/-2°C    12   -2\n21      北海公园     12/-2°C    12   -2\n22      景山公园     12/-2°C    12   -2\n23     北京海洋馆     12/-3°C    12   -3\n```\n\n### 十、数据分析\n\n本项目基于Kaggle电影影评数据集，通过这个系列，你将学到如何进行数据探索性分析(EDA)，学会使用数据分析利器`pandas`，会用绘图包`pyecharts`，以及EDA时可能遇到的各种实际问题及一些处理技巧。\n\n\n\n本项目需要导入的包：\n\n```python\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom pyecharts.charts import Bar,Grid,Line\nimport pyecharts.options as opts\nfrom pyecharts.globals import ThemeType\n```\n\n#### 1 创建DataFrame\npandas中一个dataFrame实例：\n```python\nOut[89]:\n        a  val\n0  apple1  1.0\n1  apple2  2.0\n2  apple3  3.0\n3  apple4  4.0\n4  apple5  5.0\n```\n\n我们的**目标**是变为如下结构：\n```python\na  apple1  apple2  apple3  apple4  apple5\n0     1.0     2.0     3.0     4.0     5.0\n```\n\n乍看可使用`pivot`，但很难一步到位。\n\n所以另辟蹊径，提供一种简单且好理解的方法：\n\n```python\nIn [113]: pd.DataFrame(index=[0],columns=df.a,data=dict(zip(df.a,df.val)))\nOut[113]:\na  apple1  apple2  apple3  apple4  apple5\n0     1.0     2.0     3.0     4.0     5.0\n```\n以上方法是重新创建一个DataFrame,直接把`df.a`所有可能取值作为新dataframe的列，index调整为`[0]`，注意类型必须是数组类型(array-like 或者 Index)，两个轴确定后，`data`填充数据域。\n\n```python\nIn [116]: dict(zip(df.a,df.val))\nOut[116]: {'apple1': 1.0, 'apple2': 2.0, 'apple3': 3.0, 'apple4': 4.0, 'apple5': 5.0}\n```\n\n\n\n#### 2 导入数据\n数据来自kaggle，共包括三个文件：\n\n1. movies.dat\n2. ratings.dat\n3. users.dat\n\n`movies.dat`包括三个字段：['Movie ID', 'Movie Title', 'Genre']\n\n使用pandas导入此文件：\n\n```python\nimport pandas as pd\n\nmovies = pd.read_csv('./data/movietweetings/movies.dat', delimiter='::', engine='python', header=None, names = ['Movie ID', 'Movie Title', 'Genre'])\n```\n\n导入后，显示前5行：\n\n```python\n   Movie ID                                        Movie Title  \\\n0         8      Edison Kinetoscopic Record of a Sneeze (1894)   \n1        10                La sortie des usines Lumi猫re (1895)   \n2        12                      The Arrival of a Train (1896)   \n3        25  The Oxford and Cambridge University Boat Race ...   \n4        91                         Le manoir du diable (1896)   \n5       131                           Une nuit terrible (1896)   \n6       417                      Le voyage dans la lune (1902)   \n7       439                     The Great Train Robbery (1903)   \n8       443        Hiawatha, the Messiah of the Ojibway (1903)   \n9       628                    The Adventures of Dollie (1908)  \n                                          Genre  \n0                             Documentary|Short  \n1                             Documentary|Short  \n2                             Documentary|Short  \n3                                           NaN  \n4                                  Short|Horror  \n5                           Short|Comedy|Horror  \n6  Short|Action|Adventure|Comedy|Fantasy|Sci-Fi  \n7                    Short|Action|Crime|Western  \n8                                           NaN  \n9                                  Action|Short  \n```\n\n\n\n次导入其他两个数据文件\n\n`users.dat`:\n\n```python\nusers = pd.read_csv('./data/movietweetings/users.dat', delimiter='::', engine='python', header=None, names = ['User ID', 'Twitter ID'])\nprint(users.head())\n```\n\n结果：\n\n```python\n   User ID  Twitter ID\n0        1   397291295\n1        2    40501255\n2        3   417333257\n3        4   138805259\n4        5  2452094989\n5        6   391774225\n6        7    47317010\n7        8    84541461\n8        9  2445803544\n9       10   995885060\n```\n\n\n\n`rating.data`:\n\n```python\nratings = pd.read_csv('./data/movietweetings/ratings.dat', delimiter='::', engine='python', header=None, names = ['User ID', 'Movie ID', 'Rating', 'Rating Timestamp'])\nprint(ratings.head())\n```\n\n结果：\n\n```python\n   User ID  Movie ID  Rating  Rating Timestamp\n0        1    111161      10        1373234211\n1        1    117060       7        1373415231\n2        1    120755       6        1373424360\n3        1    317919       6        1373495763\n4        1    454876      10        1373621125\n5        1    790724       8        1374641320\n6        1    882977       8        1372898763\n7        1   1229238       9        1373506523\n8        1   1288558       5        1373154354\n9        1   1300854       8        1377165712\n```\n\n **read_csv 使用说明**\n\n说明，本次导入`dat`文件使用`pandas.read_csv`函数。\n\n第一个位置参数`./data/movietweetings/ratings.dat` 表示文件的相对路径\n\n第二个关键字参数：`delimiter='::'`，表示文件分隔符使用`::`\n\n后面几个关键字参数分别代表使用的引擎，文件没有表头，所以`header`为`None;`\n\n导入后dataframe的列名使用`names`关键字设置，这个参数大家可以记住，比较有用。\n\n\n\nKaggle电影数据集第一节，我们使用数据处理利器 `pandas`， 函数`read_csv` 导入给定的三个数据文件。\n\n```python\nimport pandas as pd\n\nmovies = pd.read_csv('./data/movietweetings/movies.dat', delimiter='::', engine='python', header=None, names = ['Movie ID', 'Movie Title', 'Genre'])\nusers = pd.read_csv('./data/movietweetings/users.dat', delimiter='::', engine='python', header=None, names = ['User ID', 'Twitter ID'])\nratings = pd.read_csv('./data/movietweetings/ratings.dat', delimiter='::', engine='python', header=None, names = ['User ID', 'Movie ID', 'Rating', 'Rating Timestamp'])\n```\n\n用到的`read_csv`，某些重要的参数，如何使用在上一节也有所提到。下面开始数据探索分析(EDA)\n\n> 找出得分前10喜剧(comedy)\n\n\n\n#### 3 处理组合值\n\n表`movies`字段`Genre`表示电影的类型，可能有多个值，分隔符为`|`，取值也可能为`None`.\n\n针对这类字段取值，可使用Pandas中Series提供的`str`做一步转化，**注意它是向量级的**，下一步，如Python原生的`str`类似，使用`contains`判断是否含有`comedy`字符串：\n\n```python\nmask = movies.Genre.str.contains('comedy',case=False,na=False)\n```\n\n注意使用的两个参数：`case`, `na`\n\ncase为 False，表示对大小写不敏感；\nna Genre列某个单元格为`NaN`时，我们使用的充填值，此处填充为`False`\n\n返回的`mask`是一维的`Series`，结构与 movies.Genre相同，取值为True 或 False.\n\n观察结果：\n\n```python\n0    False\n1    False\n2    False\n3    False\n4    False\n5     True\n6     True\n7    False\n8    False\n9    False\nName: Genre, dtype: bool\n\n```\n\n\n #### 4 访问某列\n\n得到掩码mask后，pandas非常方便地能提取出目标记录：\n\n```python\ncomedy = movies[mask]\ncomdey_ids = comedy['Movie ID']\n\n```\n\n以上，在pandas中被最频率使用，不再解释。看结果`comedy_ids.head()`：\n\n```python\n5      131\n6      417\n15    2354\n18    3863\n19    4099\n20    4100\n21    4101\n22    4210\n23    4395\n25    4518\nName: Movie ID, dtype: int64\n\n```\n\n\n\n1-4介绍`数据读入`，`处理组合值`，`索引数据`等, pandas中使用较多的函数，基于Kaggle真实电影影评数据集，最后得到所有`喜剧 ID`：\n\n```python\n5      131\n6      417\n15    2354\n18    3863\n19    4099\n20    4100\n21    4101\n22    4210\n23    4395\n25    4518\nName: Movie ID, dtype: int64\n\n```\n\n下面继续数据探索之旅~\n\n#### 5 连接两个表\n\n拿到所有喜剧的ID后，要想找出其中平均得分最高的前10喜剧，需要关联另一张表：`ratings`:\n\n再回顾下ratings表结构：\n\n```python\n   User ID  Movie ID  Rating  Rating Timestamp\n0        1    111161      10        1373234211\n1        1    117060       7        1373415231\n2        1    120755       6        1373424360\n3        1    317919       6        1373495763\n4        1    454876      10        1373621125\n5        1    790724       8        1374641320\n6        1    882977       8        1372898763\n7        1   1229238       9        1373506523\n8        1   1288558       5        1373154354\n9        1   1300854       8        1377165712\n\n```\n\n\npandas 中使用`join`关联两张表，连接字段是`Movie ID`，如果顺其自然这么使用`join`：\n\n```python\ncombine = ratings.join(comedy, on='Movie ID', rsuffix='2')\n\n```\n\n左右滑动，查看完整代码\n\n大家可验证这种写法，仔细一看，会发现结果非常诡异。\n\n究其原因，这是pandas join函数使用的一个算是坑点，它在官档中介绍，连接右表时，此处右表是`comedy`，它的`index`要求是连接字段，也就是 `Movie ID`. \n\n左表的index不要求，但是要在参数 `on`中给定。\n\n**以上是要注意的一点**\n\n修改为：\n\n```python\ncombine = ratings.join(comedy.set_index('Movie ID'), on='Movie ID')\nprint(combine.head(10))\n\n```\n\n以上是OK的写法\n\n观察结果：\n\n```python\n   User ID  Movie ID  Rating  Rating Timestamp Movie Title Genre\n0        1    111161      10        1373234211         NaN   NaN\n1        1    117060       7        1373415231         NaN   NaN\n2        1    120755       6        1373424360         NaN   NaN\n3        1    317919       6        1373495763         NaN   NaN\n4        1    454876      10        1373621125         NaN   NaN\n5        1    790724       8        1374641320         NaN   NaN\n6        1    882977       8        1372898763         NaN   NaN\n7        1   1229238       9        1373506523         NaN   NaN\n8        1   1288558       5        1373154354         NaN   NaN\n9        1   1300854       8        1377165712         NaN   NaN\n\n```\n\nGenre列为`NaN`表明，这不是喜剧。需要筛选出此列不为`NaN` 的记录。\n\n#### 6 按列筛选\n\npandas最方便的地方，就是向量化运算，尽可能减少了for循环的嵌套。\n\n按列筛选这种常见需求，自然可以轻松应对。\n\n为了照顾初次接触 pandas 的朋友，分两步去写：\n\n```python\nmask = pd.notnull(combine['Genre'])\n\n```\n\n结果是一列只含`True 或 False`的值\n\n```python\nresult = combine[mask]\nprint(result.head())\n\n```\n\n结果中，Genre字段中至少含有一个Comedy字符串，表明验证了我们以上操作是OK的。\n\n```python\n    User ID  Movie ID  Rating  Rating Timestamp             Movie Title  \\\n12        1   1588173       9        1372821281      Warm Bodies (2013)   \n13        1   1711425       3        1372604878        21 & Over (2013)   \n14        1   2024432       8        1372703553   Identity Thief (2013)   \n17        1   2101441       1        1372633473  Spring Breakers (2012)   \n28        2   1431045       7        1457733508         Deadpool (2016)   \n\n                             Genre  \n12           Comedy|Horror|Romance  \n13                          Comedy  \n14    Adventure|Comedy|Crime|Drama  \n17              Comedy|Crime|Drama  \n28  Action|Adventure|Comedy|Sci-Fi  \n\n\n```\n\n\n\n截止目前已经求出所有喜剧电影`result`，前5行如下，Genre中都含有`Comedy`字符串：\n```python\n    User ID  Movie ID  Rating  Rating Timestamp             Movie Title  \\\n12        1   1588173       9        1372821281      Warm Bodies (2013)   \n13        1   1711425       3        1372604878        21 & Over (2013)   \n14        1   2024432       8        1372703553   Identity Thief (2013)   \n17        1   2101441       1        1372633473  Spring Breakers (2012)   \n28        2   1431045       7        1457733508         Deadpool (2016)   \n\n                             Genre  \n12           Comedy|Horror|Romance  \n13                          Comedy  \n14    Adventure|Comedy|Crime|Drama  \n17              Comedy|Crime|Drama  \n28  Action|Adventure|Comedy|Sci-Fi  \n```\n\n\n\n#### 7 按照Movie ID 分组\n\nresult中会有很多观众对同一部电影的打分，所以要求得分前10的喜剧，先按照`Movie ID`分组，然后求出平均值：\n```python\nscore_as_movie = result.groupby('Movie ID').mean()\n```\n\n前5行显示如下：\n```python\n               User ID  Rating  Rating Timestamp\nMovie ID                                        \n131       34861.000000     7.0      1.540639e+09\n417       34121.409091     8.5      1.458680e+09\n2354       6264.000000     8.0      1.456343e+09\n3863      43803.000000    10.0      1.430439e+09\n4099      25084.500000     7.0      1.450323e+09\n```\n\n#### 8 按照电影得分排序\n\n```python\nscore_as_movie.sort_values(by='Rating', ascending = False,inplace=True)\nscore_as_movie\n```\n前5行显示如下：\n```python\n\tUser ID\tRating\tRating Timestamp\nMovie ID\t\t\t\n7134690\t30110.0\t10.0\t1.524974e+09\n416889\t1319.0\t10.0\t1.543320e+09\n57840\t23589.0\t10.0\t1.396802e+09\n5693562\t50266.0\t10.0\t1.511024e+09\n5074\t43803.0\t10.0\t1.428352e+09\n```\n都是满分？这有点奇怪，会不会这些电影都只有几个人评分，甚至只有1个？评分样本个数太少，显然最终的平均分数不具有太强的说服力。\n\n所以，下面要进行每部电影的评分人数统计\n\n#### 9 分组后使用聚合函数\n\n根据`Movie ID`分组后，使用`count`函数统计`每组个数`，只保留count列，最后得到`watchs2`:\n\n```python\nwatchs = result.groupby('Movie ID').agg(['count'])\nwatchs2 = watchs['Rating']['count']\n```\n打印前20行：\n```python\nprint(watchs2.head(20))\n```\n结果：\n```python\nMovie ID\n131      1\n417     22\n2354     1\n3863     1\n4099     2\n4100     1\n4101     1\n4210     1\n4395     1\n4518     1\n4546     2\n4936     2\n5074     1\n5571     1\n6177     1\n6414     3\n6684     1\n6689     1\n7145     1\n7162     2\nName: count, dtype: int64\n```\n果然，竟然有这么多电影的评论数只有1次！样本个数太少，评论的平均值也就没有什么说服力。\n\n查看`watchs2`一些重要统计量：\n```python\nwatchs2.describe()\n```\n结果：\n```python\ncount    10740.000000\nmean        20.192086\nstd         86.251411\nmin          1.000000\n25%          1.000000\n50%          2.000000\n75%          7.000000\nmax       1843.000000\nName: count, dtype: float64\n```\n共有10740部**喜剧**电影被评分，平均打分次数20次，标准差86，75%的电影样本打分次数小于7次，最小1次，最多1843次。\n\n#### 10 频率分布直方图\n\n绘制评论数的频率分布直方图，便于更直观的观察电影被评论的分布情况。上面分析到，75%的电影打分次数小于7次，所以绘制打分次数小于20次的直方图：\n\n```python\nfig = plt.figure(figsize=(12,8))\nhistn = plt.hist(watchs2[watchs2 <=19],19,histtype='step')\nplt.scatter([i+1 for i in range(len(histn[0]))],histn[0])\n```\n\n![](./img/20200131094927.jpg)\n\n`histn`元祖表示个数和对应的被分割的区间，查看`histn[0]`:\n```python\narray([4383., 1507.,  787.,  541.,  356.,  279.,  209.,  163.,  158.,\n        118.,  114.,   90.,  104.,   81.,   80.,   73.,   62.,   65.,\n         52.])\n```\n```python\nsum(histn[0]) # 9222\n```\n看到电影评论次数1到19次的喜剧电影9222部，共有10740部喜剧电影，大约`86%`的喜剧电影评论次数`小于20次`，有`1518`部电影评论数不小于20次。\n\n我们肯定希望挑选出被评论次数尽可能多的电影，因为难免会有水军和滥竽充数等`异常评论`行为。那么，如何准确的量化最小抽样量呢？\n\n\n\n#### 11 最小抽样量\n\n根据统计学的知识，最小抽样量和Z值、样本方差和样本误差相关，下面给出具体的求解最小样本量的计算方法。\n\n采用如下计算公式：\n\n$$ n = \\frac{Z^2\\sigma^2}{E^2} $$\n\n\n此处，$Z$ 值取为95%的置信度对应的Z值也就是1.96，样本误差取为均值的2.5%.\n\n根据以上公式，编写下面代码：\n\n```python\nn3 = result.groupby('Movie ID').agg(['count','mean','std'])\nn3r = n3[n3['Rating']['count']>=20]['Rating']\n```\n只计算影评超过20次，且满足最小样本量的电影。计算得到的`n3r`前5行：\n```python\n\tcount\tmean\tstd\nMovie ID\t\t\t\n417\t22\t8.500000\t1.263027\n12349\t68\t8.485294\t1.227698\n15324\t20\t8.350000\t1.039990\n15864\t51\t8.431373\t1.374844\n17925\t44\t8.636364\t1.259216\n```\n进一步求出最小样本量：\n```python\nnmin = (1.96**2*n3r['std']**2) / ( (n3r['mean']*0.025)**2 )\n```\n`nmin`前5行：\n```python\nMovie ID\n417         135.712480\n12349       128.671290\n15324        95.349276\n15864       163.434005\n17925       130.668350\n```\n\n筛选出满足最小抽样量的喜剧电影：\n\n```python\nn3s = n3r[ n3r['count'] >= nmin ]\n```\n结果显示如下，因此共有`173`部电影满足最小样本抽样量。\n\n```python\n\ncount\tmean\tstd\nMovie ID\t\t\t\n53604\t129\t8.635659\t1.230714\n57012\t207\t8.449275\t1.537899\n70735\t224\t8.839286\t1.190799\n75686\t209\t8.095694\t1.358885\n88763\t296\t8.945946\t1.026984\n...\t...\t...\t...\n6320628\t860\t7.966279\t1.469924\n6412452\t276\t7.510870\t1.389529\n6662050\t22\t10.000000\t0.000000\n6966692\t907\t8.673649\t1.286455\n7131622\t1102\t7.851180\t1.751500\n173 rows × 3 columns\n```\n\n#### 12 去重和连表\n\n按照平均得分从大到小排序：\n```python\nn3s_sort = n3s.sort_values(by='mean',ascending=False)\n```\n结果：\n```python\n\tcount\tmean\tstd\nMovie ID\t\t\t\n6662050\t22\t10.000000\t0.000000\n4921860\t48\t10.000000\t0.000000\n5262972\t28\t10.000000\t0.000000\n5512872\t353\t9.985836\t0.266123\n3863552\t199\t9.010050\t1.163372\n...\t...\t...\t...\n1291150\t647\t6.327666\t1.785968\n2557490\t546\t6.307692\t1.858434\n1478839\t120\t6.200000\t0.728761\n2177771\t485\t6.150515\t1.523922\n1951261\t1091\t6.083410\t1.736127\n173 rows × 3 columns\n```\n仅靠`Movie ID`还是不知道哪些电影，连接`movies`表：\n```python\nms = movies.drop_duplicates(subset=['Movie ID'])\nms = ms.set_index('Movie ID')\nn3s_final = n3s_drops.join(ms,on='Movie ID')\n```\n\n#### 13 结果分析\n\n喜剧榜单前50名：\n```python\nMovie Title\nFive Minutes (2017)\nMSG 2 the Messenger (2015)\nAvengers: Age of Ultron Parody (2015)\nBe Somebody (2016)\nBajrangi Bhaijaan (2015)\nBack to the Future (1985)\nLa vita 鐚?bella (1997)\nThe Intouchables (2011)\nThe Sting (1973)\nCoco (2017)\nToy Story 3 (2010)\n3 Idiots (2009)\nGreen Book (2018)\nDead Poets Society (1989)\nThe Apartment (1960)\nP.K. (2014)\nThe Truman Show (1998)\nAm鑼卨ie (2001)\nInside Out (2015)\nToy Story 4 (2019)\nToy Story (1995)\nFinding Nemo (2003)\nDr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb (1964)\nHome Alone (1990)\nZootopia (2016)\nUp (2009)\nMonsters, Inc. (2001)\nLa La Land (2016)\nRelatos salvajes (2014)\nEn man som heter Ove (2015)\nSnatch (2000)\nLock, Stock and Two Smoking Barrels (1998)\nHow to Train Your Dragon 2 (2014)\nAs Good as It Gets (1997)\nGuardians of the Galaxy (2014)\nThe Grand Budapest Hotel (2014)\nFantastic Mr. Fox (2009)\nSilver Linings Playbook (2012)\nSing Street (2016)\nDeadpool (2016)\nAnnie Hall (1977)\nPride (2014)\nIn Bruges (2008)\nBig Hero 6 (2014)\nGroundhog Day (1993)\nThe Breakfast Club (1985)\nLittle Miss Sunshine (2006)\nDeadpool 2 (2018)\nThe Terminal (2004)\n```\n\n前10名评论数图：\n\n![](./img/2020013109495711.jpg)\n\n代码：\n```python\nx = n3s_final['Movie Title'][:10].tolist()[::-1]\ny = n3s_final['count'][:10].tolist()[::-1]\nbar = (\n    Bar()\n    .add_xaxis(x)\n    .add_yaxis('评论数',y,category_gap='50%')\n    .reversal_axis()\n    .set_global_opts(title_opts=opts.TitleOpts(title=\"喜剧电影被评论次数\"),\n                    toolbox_opts=opts.ToolboxOpts(),)\n)\ngrid = (\n    Grid(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))\n    .add(bar, grid_opts=opts.GridOpts(pos_left=\"30%\"))\n)\ngrid.render_notebook()\n```\n\n前10名得分图：\n\n![](./img/2020013109500812.jpg)\n\n代码：\n```python\nx = n3s_final['Movie Title'][:10].tolist()[::-1]\ny = n3s_final['mean'][:10].round(3).tolist()[::-1]\nbar = (\n    Bar()\n    .add_xaxis(x)\n    .add_yaxis('平均得分',y,category_gap='50%')\n    .reversal_axis()\n    .set_global_opts(title_opts=opts.TitleOpts(title=\"喜剧电影平均得分\"),\n                    xaxis_opts=opts.AxisOpts(min_=8.0,name='平均得分'),\n                    toolbox_opts=opts.ToolboxOpts(),)\n)\ngrid = (\n    Grid(init_opts=opts.InitOpts(theme=ThemeType.MACARONS))\n    .add(bar, grid_opts=opts.GridOpts(pos_left=\"30%\"))\n)\ngrid.render_notebook()\n```\n\n\n\n#### 14 生成哑变量\n\n分类变量的数值化，是指将枚举类变量转化为indicator变量或称dummy变量。\n\n那么什么是`indicator变量`，看看如下例子，A变量解析为：`[1,0,0]`, B解析为：`[0,1,0]`, C解析为：`[0,0,1]`\n```python\nIn [8]: s = pd.Series(list('ABCA'))\nIn [9]: pd.get_dummies(s)\nOut[9]:\n   A  B  C\n0  1  0  0\n1  0  1  0\n2  0  0  1\n3  1  0  0\n```\n\n如果输入的字符有4个唯一值，看到字符a被解析为[1,0,0,0]，向量长度为4.\n\n```python\nIn [5]: s = pd.Series(list('abaccd'))\nIn [6]: pd.get_dummies(s)\nOut[6]:\n   a  b  c  d\n0  1  0  0  0\n1  0  1  0  0\n2  1  0  0  0\n3  0  0  1  0\n4  0  0  1  0\n5  0  0  0  1\n```\n\n也就是说dummy向量的长度等于输入字符串中，唯一字符的个数。\n\n#### 15 讨厌的SettingWithCopyWarning！！！\n\nPandas 处理数据，太好用了，谁用谁知道！\n\n使用过 Pandas 的，几乎都会遇到一个警告：\n\n*SettingWithCopyWarning*\n\n非常烦人！\n\n尤其是刚接触 Pandas 的，完全不理解为什么弹出这么一串：\n\n```python\nd:\\source\\test\\settingwithcopy.py:9: SettingWithCopyWarning:\nA value is trying to be set on a copy of a slice from a DataFrame.\nTry using .loc[row_indexer,col_indexer] = value instead\n\nSee the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy \n```\n\n归根结底，是因为代码中出现`链式操作`...\n\n有人就问了，什么是`链式操作`?\n\n这样的：\n\n```python\ntmp = df[df.a<4]\ntmp['c'] = 200\n```\n\n先记住这个最典型的情况，即可！\n\n有的人就问了：出现这个 Warning, 需要理会它吗？ \n\n如果结果不对，当然要理会；如果结果对，不care.\n\n举个例子~~\n\n```python\nimport pandas as  pd\n\ndf = pd.DataFrame({'a':[1,3,5],'b':[4,2,7]},index=['a','b','c'])\ndf.loc[df.a<4,'c'] = 100\nprint(df)\nprint('it\\'s ok')\n\ntmp = df[df.a<4]\ntmp['c'] = 200\nprint('-----tmp------')\nprint(tmp)\nprint('-----df-------')\nprint(df)\n```\n\n输出结果：\n```python\n   a  b      c\na  1  4  100.0\nb  3  2  100.0\nc  5  7    NaN\nit's ok\nd:\\source\\test\\settingwithcopy.py:9: SettingWithCopyWarning:\nA value is trying to be set on a copy of a slice from a DataFrame.\nTry using .loc[row_indexer,col_indexer] = value instead\n\nSee the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy     \n  tmp['c'] = 200\n-----tmp------\n   a  b    c\na  1  4  200\nb  3  2  200\n-----df-------\n   a  b      c\na  1  4  100.0\nb  3  2  100.0\nc  5  7    NaN\n```\n\nit's ok 行后面的发生链式赋值，导致结果错误。因为 tmp 变了，df 没赋上值啊，所以必须理会。\n\nit's ok 行前的是正解。\n\n以上，链式操作尽量避免，如何避免？多使用 `.loc[row_indexer,col_indexer]`，提示告诉我们的~\n\n#### 16 NumPy 数据归一化、分布可视化\n\n仅使用 `NumPy`，下载数据，归一化，使用 `seaborn` 展示数据分布。\n\n**下载数据**\n\n```python\nimport numpy as np\n\nurl = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'\nwid = np.genfromtxt(url, delimiter=',', dtype='float', usecols=[1])\n```\n仅提取 `iris` 数据集的第二列 `usecols = [1]`\n\n**展示数据**\n\n```python\narray([3.5, 3. , 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.4, 3. ,\n       3. , 4. , 4.4, 3.9, 3.5, 3.8, 3.8, 3.4, 3.7, 3.6, 3.3, 3.4, 3. ,\n       3.4, 3.5, 3.4, 3.2, 3.1, 3.4, 4.1, 4.2, 3.1, 3.2, 3.5, 3.1, 3. ,\n       3.4, 3.5, 2.3, 3.2, 3.5, 3.8, 3. , 3.8, 3.2, 3.7, 3.3, 3.2, 3.2,\n       3.1, 2.3, 2.8, 2.8, 3.3, 2.4, 2.9, 2.7, 2. , 3. , 2.2, 2.9, 2.9,\n       3.1, 3. , 2.7, 2.2, 2.5, 3.2, 2.8, 2.5, 2.8, 2.9, 3. , 2.8, 3. ,\n       2.9, 2.6, 2.4, 2.4, 2.7, 2.7, 3. , 3.4, 3.1, 2.3, 3. , 2.5, 2.6,\n       3. , 2.6, 2.3, 2.7, 3. , 2.9, 2.9, 2.5, 2.8, 3.3, 2.7, 3. , 2.9,\n       3. , 3. , 2.5, 2.9, 2.5, 3.6, 3.2, 2.7, 3. , 2.5, 2.8, 3.2, 3. ,\n       3.8, 2.6, 2.2, 3.2, 2.8, 2.8, 2.7, 3.3, 3.2, 2.8, 3. , 2.8, 3. ,\n       2.8, 3.8, 2.8, 2.8, 2.6, 3. , 3.4, 3.1, 3. , 3.1, 3.1, 3.1, 2.7,\n       3.2, 3.3, 3. , 2.5, 3. , 3.4, 3. ])\n      \n```\n\n这是单变量(univariate)长度为 150 的一维 NumPy 数组。\n\n**归一化**\n\n求出最大值、最小值\n```python\nsmax = np.max(wid)\nsmin = np.min(wid)\n\nIn [51]: smax,smin\nOut[51]: (4.4, 2.0)\n````\n归一化公式：\n```python\ns = (wid - smin) / (smax - smin)\n```\n只打印小数点后三位设置：\n```python\nnp.set_printoptions(precision=3)  \n```\n\n归一化结果：\n```markdown\narray([0.625, 0.417, 0.5  , 0.458, 0.667, 0.792, 0.583, 0.583, 0.375,\n       0.458, 0.708, 0.583, 0.417, 0.417, 0.833, 1.   , 0.792, 0.625,\n       0.75 , 0.75 , 0.583, 0.708, 0.667, 0.542, 0.583, 0.417, 0.583,\n       0.625, 0.583, 0.5  , 0.458, 0.583, 0.875, 0.917, 0.458, 0.5  ,\n       0.625, 0.458, 0.417, 0.583, 0.625, 0.125, 0.5  , 0.625, 0.75 ,\n       0.417, 0.75 , 0.5  , 0.708, 0.542, 0.5  , 0.5  , 0.458, 0.125,\n       0.333, 0.333, 0.542, 0.167, 0.375, 0.292, 0.   , 0.417, 0.083,\n       0.375, 0.375, 0.458, 0.417, 0.292, 0.083, 0.208, 0.5  , 0.333,\n       0.208, 0.333, 0.375, 0.417, 0.333, 0.417, 0.375, 0.25 , 0.167,\n       0.167, 0.292, 0.292, 0.417, 0.583, 0.458, 0.125, 0.417, 0.208,\n       0.25 , 0.417, 0.25 , 0.125, 0.292, 0.417, 0.375, 0.375, 0.208,\n       0.333, 0.542, 0.292, 0.417, 0.375, 0.417, 0.417, 0.208, 0.375,\n       0.208, 0.667, 0.5  , 0.292, 0.417, 0.208, 0.333, 0.5  , 0.417,\n       0.75 , 0.25 , 0.083, 0.5  , 0.333, 0.333, 0.292, 0.542, 0.5  ,\n       0.333, 0.417, 0.333, 0.417, 0.333, 0.75 , 0.333, 0.333, 0.25 ,\n       0.417, 0.583, 0.458, 0.417, 0.458, 0.458, 0.458, 0.292, 0.5  ,\n       0.542, 0.417, 0.208, 0.417, 0.583, 0.417])\n```\n\n**分布可视化**\n\n```python\nimport seaborn as sns\nsns.distplot(s,kde=False,rug=True)\n```\n频率分布直方图：\n\n\n![](https://imgkr.cn-bj.ufileos.com/49bf5190-429c-4172-a53c-e3f6b66d4e64.png)\n\n\n```python\nsns.distplot(s,hist=True,kde=True,rug=True)\n```\n带高斯密度核函数的直方图：\n\n![](https://imgkr.cn-bj.ufileos.com/4e4a72a5-8f59-4893-b435-e4b57e22a18e.png)\n\n\n\n**分布 fit 图**\n\n拿 `gamma` 分布去 fit ：\n```python\nfrom scipy import stats\nsns.distplot(s, kde=False, fit = stats.gamma)\n```\n\n\n\n![](https://imgkr.cn-bj.ufileos.com/89446755-7420-4f96-97fe-c4e45d0d3dec.png)\n\n\n拿双 `gamma` 去 fit：\n```python\nfrom scipy import stats\nsns.distplot(s, kde=False, fit = stats.dgamma)\n```\n\n![](https://imgkr.cn-bj.ufileos.com/f2c2a660-5433-4b4f-ad7b-d01da4121319.png)\n\n#### 17 Pandas 使用技巧\n\n对于动辄就几十或几百个 G 的数据，在读取的这么大数据的时候，我们有没有办法随机选取一小部分数据，然后读入内存，快速了解数据和开展 EDA ？\n\n使用 Pandas 的 skiprows 和 概率知识，就能做到。\n\n下面解释具体怎么做。\n\n如下所示，读取某 100 G 大小的 big_data.csv 数据\n\n1) 使用 skiprows 参数，\n\n2) x > 0 确保首行读入， \n\n3) np.random.rand() > 0.01 表示 99% 的数据都会被随机过滤掉\n\n言外之意，只有全部数据的 1% 才有机会选入内存中。\n\n```python\nimport pandas as pd\nimport numpy as np\n\ndf = pd.read_csv(\"big_data.csv\", \nskiprows = \nlambda x: x>0 and np.random.rand() > 0.01)\n\nprint(\"The shape of the df is {}. \nIt has been reduced 100 times!\".format(df.shape))\n```\n\n使用这种方法，读取的数据量迅速缩减到原来的 1% ，对于迅速展开数据分析有一定的帮助。\n\n### 十一、一步一步掌握Flask web开发\n\n#### 1 Flask版 hello world\n\nFlask是Python轻量级web框架，容易上手，被广大Python开发者所喜爱。\n\n今天我们先从hello world开始，一步一步掌握Flask web开发。例子君是Flask框架的小白，接下来与读者朋友们，一起学习这个对我而言的新框架，大家多多指导。\n\n首先`pip install Flask`,安装Flask，然后import Flask，同时创建一个 `app`\n```python\nfrom flask import Flask\n\nApp = Flask(__name__)\n```\n\n写一个index页的入口函数，返回hello world.\n\n通过装饰器：App.route('/')创建index页的路由或地址，一个`/`表示index页，也就是主页。\n\n```python\n@App.route('/')\ndef index():\n    return \"hello world\"\n```\n\n调用 `index`函数:\n```python\nif __name__ == \"__main__\":\n    App.run(debug=True)\n```\n\n然后启动，会在console下看到如下启动信息，表明`服务启动成功`。\n```python\n* Debug mode: on\n * Restarting with stat\n * Debugger is active!\n * Debugger PIN: 663-788-611\n * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n```\n\n 接下来，打开一个网页，相当于启动客户端，并在Url栏中输入：`http://127.0.0.1:5000/`，看到页面上答应出`hello world`，证明服务访问成功。\n\n 同时在服务端后台看到如下信息，表示处理一次来自客户端的`get`请求。\n ```python\n 27.0.0.1 - - [03/Feb/2020 21:26:50] \"GET / HTTP/1.1\" 200 -\n ```\n\n 以上就是flask的hello world 版\n\n#### 2 Flask之数据入库操作\n\n数据持久化就是将数据写入到数据库存储的过程。\n\n本例子使用`sqlite3`数据库。\n\n1)导入`sqlite3`，未安装前使用命令`pip install sqlite3`\n\n创建一个`py`文件：`sqlite3_started.py`，并写下第一行代码：\n```python\nimport sqlite3\n```\n2)手动创建一个数据库实例`db`, 命名`test.db`\n\n3)创建与数据库实例`test.db`的连接:\n```python\nconn = sqlite3.connect(\"test.db\")\n```\n\n4)拿到连接`conn`的cursor\n```python\nc = conn.cursor()\n```\n\n5)创建第一张表`books`\n\n共有四个字段：`id`,`sort`,`name`,`price`，类型分别为：`int`,`int`,`text`,`real`. 其中`id`为`primary key`. 主键的取值必须是唯一的(`unique`)，否则会报错。\n\n\n```python\nc.execute('''CREATE TABLE books\n      (id int primary key,\n       sort int,\n       name text,\n       price real)''')\n```\n第一次执行上面语句，表`books`创建完成。当再次执行时，就会报`重复建表`的错误。需要优化脚本，检查表是否存在`IF NOT EXISTS books`，不存在再创建：\n```python\nc.execute('''CREATE TABLE IF NOT EXISTS books\n      (id int primary key,\n       sort int,\n       name text,\n       price real)''')\n```\n\n6)插入一行记录\n\n共为4个字段赋值\n\n```python\nc.execute('''INSERT INTO books VALUES\n       (1, \n       1, \n       'computer science',\n       39.0)''')\n```\n\n7)一次插入多行记录\n\n先创建一个list:`books`，使用`executemany`一次插入多行。\n```python\nbooks = [(2, 2, 'Cook book', 68),\n         (3, 2, 'Python intro', 89),\n         (4, 3, 'machine learning', 59),\n         ]\n\n\nc.executemany('INSERT INTO books VALUES (?, ?, ?, ?)', books)\n```\n\n8)提交\n\n提交后才会真正生效，写入到数据库\n\n```python\nconn.commit()\n```\n\n9)关闭期初建立的连接conn\n\n务必记住手动关闭，否则会出现内存泄漏\n```python\nconn.close()\nprint('Done')\n```\n\n10)查看结果\n例子君使用`vs code`，在扩展库中选择：`SQLite`安装。\n\n![image-20200208211721377](./img/image-20200208211721377.png)\n\n新建一个`sq`文件：`a.sql`，内容如下：\n\n```sql\nSELECT * from books \n```\n右键`run query`，得到表`books`插入的4行记录可视化图：\n\n![image-20200208211806853](./img/image-20200208211806853.png)\n\n以上十步就是sqlite3写入数据库的主要步骤，作为Flask系列的第二篇，为后面的前端讲解打下基础。\n\n#### 3 Flask各层调用关系\n\n这篇介绍Flask和B/S模式，即浏览器/服务器模式，是接下来快速理解Flask代码的关键理论篇：**理解Views、models和渲染模板层的调用关系**。\n\n1) 发出请求\n\n当我们在浏览器地址栏中输入某个地址，按回车后，完成第一步。\n\n2) 视图层 views接收1)步发出的请求，Flask中使用解释器的方式处理这个求情，实例代码如下，它通常涉及到调用models层和模板文件层\n\n```python\n@main_blue.route('/', methods=['GET', 'POST'])\ndef index():\n    form = TestForm()\n    print('test')\n```\n\n3) models层会负责创建数据模型，执行CRUD操作\n\n4) 模板文件层处理html模板\n\n5) 组合后返回html\n\n6) models层和html模板组合后返回给views层\n\n7）最后views层响应并渲染到浏览器页面，我们就能看到请求的页面。\n\n完整过程图如下所示：\n\n![image-20200211152007983](./img/web1.png)\n\n读者朋友们，如果你和例子君一样都是初学Flask编程，需要好好理解上面的过程。理解这些对于接下来的编程会有一定的理论指导，方向性指导价值。\n\n### Python 问答\n\n#### Python 如何生成二维码？\n\n\n\n\n\n## qrcode\n\n今天先来解答如何生成二维码。Python的`qrcode`包支持生成二维码。\n\n用法也很简单：\n\n```python\nimport qrcode\n\n# 二维码内容\ndata = \"http://www.zglg.work/wp-content/uploads/2020/10/image-3.png\"\n# 生成二维码\nimg = qrcode.make(data=data)\n# 直接显示二维码\nimg.show()\n# 保存二维码为文件\nimg.save(\"我的微信.jpg\")\n```\n\n生成的二维码如下：\n\n![](https://imgkr2.cn-bj.ufileos.com/f0b08c53-0107-483b-bbe5-072bebc58e8d.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=rVtaeBWhzLPPq%252BFCVtiOv6rS0tI%253D&Expires=1603544615)\n\n\n大家微信扫描后，会出现我的二维码。\n\n另外，还可以设置二维码的颜色等样式：\n\n```python\nimport qrcode\n\n# 实例化二维码生成类\nqr = qrcode.QRCode(border=2)\n# 设置二维码数据\ndata = \"http://www.zglg.work/wp-content/uploads/2020/10/image-3.png\"\nqr.add_data(data=data)\n# 启用二维码颜色设置\nqr.make(fit=True)\nimg = qr.make_image(fill_color=\"orange\", back_color=\"white\")\n\n# 显示二维码\nimg.show()\n```\n\n生成一个orange的二维码：\n\n![](https://imgkr2.cn-bj.ufileos.com/cbd26fd8-27cf-4630-935f-6896822ce483.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=uy1r24x%252Fp5QpI5Wy10Ebdaz%252BpLM%253D&Expires=1603544681)\n\n更多样式，大家可以自己去玩耍。\n\n## Python小项目：句子KWIC显示\n\n上下文关键字（KWIC, Key Word In Context）是最常见的多行协调显示格式。\n\n此小项目描述：输入一系列句子，给定一个给定单词，每个句子中至少会出现一次给定单词。目标输出，给定单词按照KWIC显示，KWIC显示的基本要求：待查询单词居中，前面`pre`序列右对齐，后面`post`序列左对齐，待查询单词前和后长度相等，若输入句子无法满足要求，用空格填充。\n\n输入参数：输入句子sentences, 待查询单词selword, 滑动窗口长度`window_len`\n\n举例，输入如下六个句子，给定单词`secure`，输出如下字符串：\n\n```python\n               pre keyword    post \n\n     welfare , and secure  the blessings of\n     nations , and secured immortal glory with \n       , and shall secure  to you the \n    cherished . To secure  us against these \n     defense as to secure  our cities and \n          I can to secure  economy and fidelity \n```\n\n请补充实现下面函数：\n\n```python\ndef kwic(sentences: List[str], selword: str, window_len: int) -> str:\n    \"\"\"\n    :type: sentences: input sentences\n    :type: selword: selected word\n    :type: window_len: window length\n    \"\"\"\n```\n\n更多KWIC显示参考如下：\n\nhttp://dep.chs.nihon-u.ac.jp/english_lang/tukamoto/kwic_e.html\n\n完整代码已经公布在：http://www.zglg.work/Python-20-topics/python-project1-kwic/\n![image](https://user-images.githubusercontent.com/20391209/123213609-c494dc00-d4f8-11eb-84d6-4d8caabb44f7.png)\n![image](https://user-images.githubusercontent.com/20391209/123213901-26eddc80-d4f9-11eb-96cd-d3518005c4df.png)\n\n"
  },
  {
    "path": "md/1.md",
    "content": "```markdown\r\n@author jackzhenguo\r\n@desc 实现 relu\r\n@date 2019/2/10\r\n```\r\n\r\n#### 1 实现 relu\r\n\r\n在神经网络中，`relu`作为神经元的激活函数：\r\n\r\n```python\r\ndef relu(x):\r\n    \"\"\"\r\n    x: 输入参数\r\n    return：输出relu值\r\n    \"\"\"\r\n    return max(0,x)                                                                 \r\n```\r\n\r\n测试：\r\n\r\n```python\r\nrelu(5) # 5\r\n\r\nrelu(-1) # 0\r\n```\r\n\r\n\r\n\r\n<center>[下一个例子](2.md)</center>\r\n"
  },
  {
    "path": "md/10.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/15\n```\n\n#### 10  转为整型　　\n\nint(x, base =10) , x可能为字符串或数值，将 x 转换为一个普通整数。\n\n参数base指定x进制数，常见的2，8，10，16分别表示二进制、八进制、十进制、十六进制的数字\n\n如果参数是字符串，必须为整数型字符串，如果是浮点数字符串会抛出异常。\n\n如果x是浮点数，int后截去小数点，只保留整数部分。\n\n```python\nIn [2]: int('0110',2)\n\nOut[2]: 6\n\nIn [3]: int('0732',8)\nOut[3]: 474\n\nIn [4]: int('12',16)\nOut[4]: 18\n\nIn [5]: int('12',10)\nOut[5]: 12\n\nIn [6]: int(1.45)\nOut[6]: 1\n\nIn [7]: int('1.45')\n---------------------------------------------------------------------------\nValueError                                Traceback (most recent call last)\n<ipython-input-7-6cf4b951408f> in <module>\n----> 1 int('1.45')\n\nValueError: invalid literal for int() with base 10: '1.45'\n```\n\n\n<center>[上一个例子](9.md)    [下一个例子](11.md)</center>\n"
  },
  {
    "path": "md/100.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/9/3\n```\n\n#### 100 是否互为排序词\n\n排序词(permutation)：两个字符串含有相同字符，但字符顺序不同。\n\n```python\nfrom collections import defaultdict\n\n\ndef is_permutation(str1, str2):\n    if str1 is None or str2 is None:\n        return False\n    if len(str1) != len(str2):\n        return False\n    unq_s1 = defaultdict(int)\n    unq_s2 = defaultdict(int)\n    for c1 in str1:\n        unq_s1[c1] += 1\n    for c2 in str2:\n        unq_s2[c2] += 1\n\n    return unq_s1 == unq_s2\n```\n\n这个小例子，使用python内置的`defaultdict`，默认类型初始化为`int`，计数默次数都为0. 这个解法本质是 `hash map lookup`\n\n统计出的两个defaultdict：unq_s1，unq_s2，如果相等，就表明str1、 str2互为排序词。\n\n下面测试：\n\n```python\nr = is_permutation('nice', 'cine')\nprint(r)  # True\n\nr = is_permutation('', '')\nprint(r)  # True\n\nr = is_permutation('', None)\nprint(r)  # False\n\nr = is_permutation('work', 'woo')\nprint(r)  # False\n\n```\n\n<center>[上一个例子](99.md)    [下一个例子](101.md)</center>"
  },
  {
    "path": "md/101.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/9/4\n```\n\n#### 101 str1是否由str2旋转而来\n\n`stringbook`旋转后得到`bookstring`,写一段代码验证`str1`是否为`str2`旋转得到。\n\n**思路**\n\n转化为判断：`str1`是否为`str2+str2`的子串\n\n```python\ndef is_rotation(s1: str, s2: str) -> bool:\n    if s1 is None or s2 is None:\n        return False\n    if len(s1) != len(s2):\n        return False\n\n    def is_substring(s1: str, s2: str) -> bool:\n        return s1 in s2\n    return is_substring(s1, s2 + s2)\n```\n\n**测试**\n\n```python\nr = is_rotation('stringbook', 'bookstring')\nprint(r)  # True\n\nr = is_rotation('greatman', 'maneatgr')\nprint(r)  # False\n```\n\n<center>[上一个例子](100.md)    [下一个例子](102.md)</center>"
  },
  {
    "path": "md/102.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/9/9\n```\n\n#### 102 使用正则判断是否为正浮点数\n\n从一系列字符串中，挑选出所有正浮点数。\n\n该怎么办？\n\n玩玩正则表达式，用正则搞它！\n\n关键是，正则表达式该怎么写呢？\n\n有了！\n\n`^[1-9]\\d*\\.\\d*$`\n\n`^` 表示字符串开始\n\n`[1-9]` 表示数字1,2,3,4,5,6,7,8,9\n\n`^[1-9]` 连起来表示以数字 `1-9` 作为开头\n\n`\\d` 表示一位 `0-9` 的数字\n\n`*` 表示前一位字符出现 0 次，1 次或多次\n\n`\\d*` 表示数字出现 0 次，1 次或多次 \n\n`\\.` 表示小数点\n\n`\\$` 表示字符串以前一位的字符结束\n\n`^[1-9]\\d*\\.\\d*$` 连起来就求出所有大于 1.0 的正浮点数。\n\n那 0.0 到 1.0 之间的正浮点数，怎么求，干嘛不直接汇总到上面的正则表达式中呢？\n\n这样写不行吗：`^[0-9]\\d*\\.\\d*$`\n\n```python\nIn [85]: import re\n\nIn [87]: recom = re.compile(r'^[0-9]\\d*\\.\\d*$')\n\nIn [88]: recom.match('000.2')\nOut[88]: <re.Match object; span=(0, 5), match='000.2'>\n```\n\n结果显示，正则表达式 `^[0-9]\\d*\\.\\d*$` 竟然匹配到 `000.2 `，认为它是一个正浮点数。\n\n所以知道为啥要先匹配大于 1.0 的浮点数了吧！\n\n如果能写出这个正则表达式，再写另一部分就不困难了！\n\n0.0 到 1.0 间的浮点数：`^0\\.\\d*[1-9]\\d*$`\n\n两个式子连接起来就是最终的结果：\n\n`^[1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*$`\n\n<center>[上一个例子](101.md)    [下一个例子](103.md)</center>"
  },
  {
    "path": "md/103.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/9/10\n```\n\n#### 103 获取后缀名\n\n```python\nimport os\nfile_ext = os.path.splitext('./data/py/test.py')\nfront,ext = file_ext\nIn [5]: front\nOut[5]: './data/py/test'\n\nIn [6]: ext\nOut[6]: '.py'\n```\n\n<center>[上一个例子](102.md)    [下一个例子](104.md)</center>"
  },
  {
    "path": "md/104.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/10/3\n```\n\n#### 104 获取路径中的文件名\n\n```python\nIn [11]: import os\n    ...: file_ext = os.path.split('./data/py/test.py')\n    ...: ipath,ifile = file_ext\n    ...:\n\nIn [12]: ipath\nOut[12]: './data/py'\n\nIn [13]: ifile\nOut[13]: 'test.py'\n```\n\n<center>[上一个例子](103.md)    [下一个例子](105.md)</center>"
  },
  {
    "path": "md/105.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/10/4\n```\n\n#### 105 批量修改文件后缀\n\n**批量修改文件后缀**\n\n本例子使用Python的`os`模块和 `argparse`模块，将工作目录`work_dir`下所有后缀名为`old_ext`的文件修改为后缀名为`new_ext`\n\n通过本例子，大家将会大概清楚`argparse`模块的主要用法。\n\n导入模块\n\n```python\nimport argparse\nimport os\n```\n\n定义脚本参数\n\n```python\ndef get_parser():\n    parser = argparse.ArgumentParser(\n        description='工作目录中文件后缀名修改')\n    parser.add_argument('work_dir', metavar='WORK_DIR', type=str, nargs=1,\n                        help='修改后缀名的文件目录')\n    parser.add_argument('old_ext', metavar='OLD_EXT',\n                        type=str, nargs=1, help='原来的后缀')\n    parser.add_argument('new_ext', metavar='NEW_EXT',\n                        type=str, nargs=1, help='新的后缀')\n    return parser\n```\n\n后缀名批量修改\n\n```python\ndef batch_rename(work_dir, old_ext, new_ext):\n    \"\"\"\n    传递当前目录，原来后缀名，新的后缀名后，批量重命名后缀\n    \"\"\"\n    for filename in os.listdir(work_dir):\n        # 获取得到文件后缀\n        split_file = os.path.splitext(filename)\n        file_ext = split_file[1]\n        # 定位后缀名为old_ext 的文件\n        if old_ext == file_ext:\n            # 修改后文件的完整名称\n            newfile = split_file[0] + new_ext\n            # 实现重命名操作\n            os.rename(\n                os.path.join(work_dir, filename),\n                os.path.join(work_dir, newfile)\n            )\n    print(\"完成重命名\")\n    print(os.listdir(work_dir))\n```\n\n实现Main\n\n```python\ndef main():\n    \"\"\"\n    main函数\n    \"\"\"\n    # 命令行参数\n    parser = get_parser()\n    args = vars(parser.parse_args())\n    # 从命令行参数中依次解析出参数\n    work_dir = args['work_dir'][0]\n    old_ext = args['old_ext'][0]\n    if old_ext[0] != '.':\n        old_ext = '.' + old_ext\n    new_ext = args['new_ext'][0]\n    if new_ext[0] != '.':\n        new_ext = '.' + new_ext\n\n    batch_rename(work_dir, old_ext, new_ext)\n```\n\n<center>[上一个例子](104.md)    [下一个例子](106.md)</center>"
  },
  {
    "path": "md/106.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/10/5\n```\n\n#### 106 xls批量转换成xlsx\n\n```python\nimport os\n\n\ndef xls_to_xlsx(work_dir):\n    \"\"\"\n    传递当前目录，原来后缀名，新的后缀名后，批量重命名后缀\n    \"\"\"\n    old_ext, new_ext = '.xls', '.xlsx'\n    for filename in os.listdir(work_dir):\n        # 获取得到文件后缀\n        split_file = os.path.splitext(filename)\n        file_ext = split_file[1]\n        # 定位后缀名为old_ext 的文件\n        if old_ext == file_ext:\n            # 修改后文件的完整名称\n            newfile = split_file[0] + new_ext\n            # 实现重命名操作\n            os.rename(\n                os.path.join(work_dir, filename),\n                os.path.join(work_dir, newfile)\n            )\n    print(\"完成重命名\")\n    print(os.listdir(work_dir))\n\n\nxls_to_xlsx('./data')\n\n# 输出结果：\n# ['cut_words.csv', 'email_list.xlsx', 'email_test.docx', 'email_test.jpg', 'email_test.xlsx', 'geo_data.png', 'geo_data.xlsx',\n'iotest.txt', 'pyside2.md', 'PySimpleGUI-4.7.1-py3-none-any.whl', 'test.txt', 'test_excel.xlsx', 'ziptest', 'ziptest.zip']\n```\n\n<center>[上一个例子](105.md)    [下一个例子](107.md)</center>"
  },
  {
    "path": "md/107.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/10/6\n```\n\n#### 107 获取指定后缀名的文件\n\n```python\nimport os\n\ndef find_file(work_dir,extension='jpg'):\n    lst = []\n    for filename in os.listdir(work_dir):\n        print(filename)\n        splits = os.path.splitext(filename)\n        ext = splits[1] # 拿到扩展名\n        if ext == '.'+extension:\n            lst.append(filename)\n    return lst\n\nr = find_file('.','md') \nprint(r) # 返回所有目录下的md文件\n```\n\n<center>[上一个例子](106.md)    [下一个例子](108.md)</center>"
  },
  {
    "path": "md/108.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/10/8\n```\n\n#### 108 批量压缩文件\n\n\n```python\nimport zipfile  # 导入zipfile,这个是用来做压缩和解压的Python模块；\nimport os\nimport time\n\n\ndef batch_zip(start_dir):\n    start_dir = start_dir  # 要压缩的文件夹路径\n    file_news = start_dir + '.zip'  # 压缩后文件夹的名字\n\n    z = zipfile.ZipFile(file_news, 'w', zipfile.ZIP_DEFLATED)\n    for dir_path, dir_names, file_names in os.walk(start_dir):\n        # 这一句很重要，不replace的话，就从根目录开始复制\n        f_path = dir_path.replace(start_dir, '')\n        f_path = f_path and f_path + os.sep  # 实现当前文件夹以及包含的所有文件的压缩\n        for filename in file_names:\n            z.write(os.path.join(dir_path, filename), f_path + filename)\n    z.close()\n    return file_news\n\n\nbatch_zip('./data/ziptest')\n\n\n```\n\n<center>[上一个例子](107.md)    [下一个例子](109.md)</center>"
  },
  {
    "path": "md/109.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/10/10\n```\n\n#### 109 32位加密\n\n```python\nimport hashlib\n# 对字符串s实现32位加密\n\n\ndef hash_cry32(s):\n    m = hashlib.md5()\n    m.update((str(s).encode('utf-8')))\n    return m.hexdigest()\n\n\nprint(hash_cry32(1))  # c4ca4238a0b923820dcc509a6f75849b\nprint(hash_cry32('hello'))  # 5d41402abc4b2a76b9719d911017c592\n```\n\n<center>[上一个例子](108.md)    [下一个例子](110.md)</center>"
  },
  {
    "path": "md/11.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/15\n```\n\n#### 11 次幂\n\nbase为底的exp次幂，如果mod给出，取余\n\n```python\nIn [1]: pow(2,1.5)                                                              \nOut[1]: 2.8284271247461903\n\nIn [1]: pow(3, 2, 4) # 3的2次方结果再对4取余数\nOut[1]: 1\n```\n\n\n<center>[上一个例子](10.md)    [下一个例子](12.md)</center>\n"
  },
  {
    "path": "md/110.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/10/12\n```\n\n#### 110 年的日历图\n\n```python\nimport calendar\nfrom datetime import date\nmydate = date.today()\nyear_calendar_str = calendar.calendar(2019)\nprint(f\"{mydate.year}年的日历图：{year_calendar_str}\\n\")\n```\n\n打印结果：\n\n```python\n2019\n\n      January                   February                   March\nMo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su\n    1  2  3  4  5  6                   1  2  3                   1  2  3\n 7  8  9 10 11 12 13       4  5  6  7  8  9 10       4  5  6  7  8  9 10\n14 15 16 17 18 19 20      11 12 13 14 15 16 17      11 12 13 14 15 16 17\n21 22 23 24 25 26 27      18 19 20 21 22 23 24      18 19 20 21 22 23 24\n28 29 30 31               25 26 27 28               25 26 27 28 29 30 31\n\n       April                      May                       June\nMo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su\n 1  2  3  4  5  6  7             1  2  3  4  5                      1  2\n 8  9 10 11 12 13 14       6  7  8  9 10 11 12       3  4  5  6  7  8  9\n15 16 17 18 19 20 21      13 14 15 16 17 18 19      10 11 12 13 14 15 16\n22 23 24 25 26 27 28      20 21 22 23 24 25 26      17 18 19 20 21 22 23\n29 30                     27 28 29 30 31            24 25 26 27 28 29 30\n\n        July                     August                  September\nMo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su\n 1  2  3  4  5  6  7                1  2  3  4                         1\n 8  9 10 11 12 13 14       5  6  7  8  9 10 11       2  3  4  5  6  7  8\n15 16 17 18 19 20 21      12 13 14 15 16 17 18       9 10 11 12 13 14 15\n22 23 24 25 26 27 28      19 20 21 22 23 24 25      16 17 18 19 20 21 22\n29 30 31                  26 27 28 29 30 31         23 24 25 26 27 28 29\n                                                    30\n\n      October                   November                  December\nMo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su\n    1  2  3  4  5  6                   1  2  3                         1\n 7  8  9 10 11 12 13       4  5  6  7  8  9 10       2  3  4  5  6  7  8\n14 15 16 17 18 19 20      11 12 13 14 15 16 17       9 10 11 12 13 14 15\n21 22 23 24 25 26 27      18 19 20 21 22 23 24      16 17 18 19 20 21 22\n28 29 30 31               25 26 27 28 29 30         23 24 25 26 27 28 29\n                                                    30 31\n```\n\n<center>[上一个例子](109.md)    [下一个例子](111.md)</center>"
  },
  {
    "path": "md/111.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/10/13\n```\n\n#### 111 判断是否为闰年\n\n```python\nimport calendar\nfrom datetime import date\n\nmydate = date.today()\nis_leap = calendar.isleap(mydate.year)\nprint_leap_str = \"%s年是闰年\" if is_leap else \"%s年不是闰年\\n\"\nprint(print_leap_str % mydate.year)\n```\n\n打印结果：\n\n```python\n2019年不是闰年\n```\n\n<center>[上一个例子](110.md)    [下一个例子](112.md)</center>"
  },
  {
    "path": "md/112.md",
    "content": "#### 112 判断月有几天\n\n```python\nimport calendar\nfrom datetime import date\n\nmydate = date.today()\nweekday, days = calendar.monthrange(mydate.year, mydate.month)\nprint(f'{mydate.year}年-{mydate.month}月的第一天是那一周的第{weekday}天\\n')\nprint(f'{mydate.year}年-{mydate.month}月共有{days}天\\n')\n```\n\n打印结果：\n\n```python\n2019年-12月的第一天是那一周的第6天\n\n2019年-12月共有31天\n```\n\n<center>[上一个例子](111.md)    [下一个例子](113.md)</center>"
  },
  {
    "path": "md/113.md",
    "content": "#### 113 月的第一天\n\n```python\nfrom datetime import date\nmydate = date.today()\nmonth_first_day = date(mydate.year, mydate.month, 1)\nprint(f\"当月第一天:{month_first_day}\\n\")\n```\n\n打印结果：\n\n```python\n# 当月第一天:2019-12-01\n```\n\n<center>[上一个例子](112.md)    [下一个例子](114.md)</center>"
  },
  {
    "path": "md/114.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/10/14\n```\n\n#### 114 月最后一天\n\n```python\nfrom datetime import date\nimport calendar\nmydate = date.today()\n_, days = calendar.monthrange(mydate.year, mydate.month)\nmonth_last_day = date(mydate.year, mydate.month, days)\nprint(f\"当月最后一天:{month_last_day}\\n\")\n```\n\n打印结果：\n\n```python\n当月最后一天:2019-12-31\n```\n\n<center>[上一个例子](113.md)    [下一个例子](115.md)</center>"
  },
  {
    "path": "md/115.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/10/15\n```\n\n#### 115 获取当前时间\n\n```python\nfrom datetime import date, datetime\nfrom time import localtime, strftime\n\ntoday_date = date.today()\nprint(today_date)  # 2019-12-22\n\ntoday_time = datetime.today()\nprint(today_time)  # 2019-12-22 18:02:33.398894\n\nlocal_time = localtime()\nprint(strftime(\"%Y-%m-%d %H:%M:%S\", local_time))  # 转化为定制的格式 2019-12-22 18:13:41\n```\n\n<center>[上一个例子](114.md)    [下一个例子](116.md)</center>"
  },
  {
    "path": "md/116.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/10/16\n```\n\n#### 116 字符时间转时间\n\n```python\nfrom time import strptime\n\n# parse str time to struct time\nstruct_time = strptime('2019-12-22 10:10:08', \"%Y-%m-%d %H:%M:%S\")\nprint(struct_time) # struct_time类型就是time中的一个类\n\n# time.struct_time(tm_year=2019, tm_mon=12, tm_mday=22, tm_hour=10, tm_min=10, tm_sec=8, tm_wday=6, tm_yday=356, tm_isdst=-1)\n```\n\n<center>[上一个例子](115.md)    [下一个例子](117.md)</center>"
  },
  {
    "path": "md/117.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/10/16\n```\n\n#### 117 时间转字符时间\n\n```python\nfrom time import strftime, strptime, localtime\n\nIn [2]: print(localtime()) #这是输入的时间\nOut[2]: time.struct_time(tm_year=2019, tm_mon=12, tm_mday=22, tm_hour=18, tm_min=24, tm_sec=56, tm_wday=6, tm_yday=356, tm_isdst=0)\n\nprint(strftime(\"%m-%d-%Y %H:%M:%S\", localtime()))  # 转化为定制的格式\n# 这是字符串表示的时间：   12-22-2019 18:26:21\n```\n\n<center>[上一个例子](116.md)    [下一个例子](118.md)</center>"
  },
  {
    "path": "md/118.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/10/21\n```\n\n#### 118 默认启动主线程\n\n一般的，程序默认执行只在一个线程，这个线程称为主线程，例子演示如下：\n\n导入线程相关的模块 `threading`:\n\n```python\nimport threading\n```\n\nthreading的类方法 `current_thread()`返回当前线程：\n\n```python\nt = threading.current_thread()\nprint(t) # <_MainThread(MainThread, started 139908235814720)>\n```\n\n所以，验证了程序默认是在`MainThead`中执行。\n\n`t.getName()`获得这个线程的名字，其他常用方法，`t.ident`获得线程`id`,`isAlive()`判断线程是否存活等。\n\n```python\nprint(t.getName()) # MainThread\nprint(t.ident) # 139908235814720\nprint(t.isAlive()) # True\n```\n\n<center>[上一个例子](117.md)    [下一个例子](119.md)</center>\n"
  },
  {
    "path": "md/119.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/10/23\n```\n\n#### 119 创建线程\n\n创建一个线程：\n\n```python\nmy_thread = threading.Thread()\n```\n\n创建一个名称为`my_thread`的线程：\n\n```python\nmy_thread = threading.Thread(name='my_thread')\n```\n\n创建线程的目的是告诉它帮助我们做些什么，做些什么通过参数`target`传入，参数类型为`callable`，函数就是可调用的：\n\n```python\ndef print_i(i):\n    print('打印i:%d'%(i,))\nmy_thread = threading.Thread(target=print_i,args=(1,))\n```\n\n`my_thread`线程已经全副武装，但是我们得按下发射按钮，启动start()，它才开始真正起飞。\n\n```python\nmy_thread().start()\n```\n\n打印结果如下，其中`args`指定函数`print_i`需要的参数i，类型为元祖。\n\n```python\n打印i:1\n```\n\n至此，多线程相关的核心知识点，已经总结完毕。但是，仅仅知道这些，还不够！光纸上谈兵，当然远远不够。\n\n<center>[上一个例子](118.md)    [下一个例子](120.md)</center>"
  },
  {
    "path": "md/12.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/15\n```\n\n#### 12 四舍五入\n\n四舍五入，`ndigits`代表小数点后保留几位：\n\n```python\nIn [11]: round(10.0222222, 3)\nOut[11]: 10.022\n\nIn [12]: round(10.05,1)\nOut[12]: 10.1\n```\n\n\n<center>[上一个例子](11.md)    [下一个例子](13.md)</center>"
  },
  {
    "path": "md/120.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/10/24\n```\n\n#### 120 交替获得CPU时间片\n\n为了更好解释，假定计算机是单核的，尽管对于`cpython`，这个假定有些多余。\n\n开辟3个线程，装到`threads`中:\n\n```python\nimport time\nfrom datetime import datetime\nimport threading\n\n\ndef print_time():\n    for _ in range(5): # 在每个线程中打印5次\n        time.sleep(0.1) # 模拟打印前的相关处理逻辑\n        print('当前线程%s,打印结束时间为:%s'%(threading.current_thread().getName(),datetime.today()))\n\n\nthreads = [threading.Thread(name='t%d'%(i,),target=print_time) for i in range(3)]\n```\n\n启动3个线程：\n\n```python\n[t.start() for t in threads]\n```\n\n打印结果如下，`t0`,`t1`,`t2`三个线程，根据操作系统的调度算法，轮询获得CPU时间片，注意观察，`t2`线程可能被连续调度，从而获得时间片。\n\n```markdown\n当前线程t0,打印结束时间为:2020-01-12 02:27:15.705235\n当前线程t1,打印结束时间为:2020-01-12 02:27:15.705402\n当前线程t2,打印结束时间为:2020-01-12 02:27:15.705687\n当前线程t0,打印结束时间为:2020-01-12 02:27:15.805767\n当前线程t1,打印结束时间为:2020-01-12 02:27:15.805886\n当前线程t2,打印结束时间为:2020-01-12 02:27:15.806044\n当前线程t0,打印结束时间为:2020-01-12 02:27:15.906200\n当前线程t2,打印结束时间为:2020-01-12 02:27:15.906320\n当前线程t1,打印结束时间为:2020-01-12 02:27:15.906433\n当前线程t0,打印结束时间为:2020-01-12 02:27:16.006581\n当前线程t1,打印结束时间为:2020-01-12 02:27:16.006766\n当前线程t2,打印结束时间为:2020-01-12 02:27:16.007006\n当前线程t2,打印结束时间为:2020-01-12 02:27:16.107564\n当前线程t0,打印结束时间为:2020-01-12 02:27:16.107290\n当前线程t1,打印结束时间为:2020-01-12 02:27:16.107741\n```\n\n<center>[上一个例子](119.md)    [下一个例子](121.md)</center>"
  },
  {
    "path": "md/121.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/10/25\n```\n\n#### 121 多线程抢夺同一个变量\n\n多线程编程，存在抢夺同一个变量的问题。\n\n比如下面例子，创建的10个线程同时竞争全局变量`a`:\n\n\n```python\nimport threading\n\n\na = 0\ndef add1():\n    global a    \n    a += 1\n    print('%s  adds a to 1: %d'%(threading.current_thread().getName(),a))\n    \nthreads = [threading.Thread(name='t%d'%(i,),target=add1) for i in range(10)]\n[t.start() for t in threads]\n```\n\n执行结果：\n\n```python\nt0  adds a to 1: 1\nt1  adds a to 1: 2\nt2  adds a to 1: 3\nt3  adds a to 1: 4\nt4  adds a to 1: 5\nt5  adds a to 1: 6\nt6  adds a to 1: 7\nt7  adds a to 1: 8\nt8  adds a to 1: 9\nt9  adds a to 1: 10\n```\n\n结果一切正常，每个线程执行一次，把`a`的值加1，最后`a` 变为10，一切正常。\n\n运行上面代码十几遍，一切也都正常。\n\n所以，我们能下结论：这段代码是线程安全的吗？\n\nNO！\n\n多线程中，只要存在同时读取和修改一个全局变量的情况，如果不采取其他措施，就一定不是线程安全的。\n\n尽管，有时，某些情况的资源竞争，暴露出问题的概率`极低极低`：\n\n本例中，如果线程0 在修改a后，其他某些线程还是get到的是没有修改前的值，就会暴露问题。\n\n\n\n但是在本例中，`a = a + 1`这种修改操作，花费的时间太短了，短到我们无法想象。所以，线程间轮询执行时，都能get到最新的a值。所以，暴露问题的概率就变得微乎其微。\n\n<center>[上一个例子](120.md)    [下一个例子](122.md)</center>"
  },
  {
    "path": "md/122.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/10/28\n```\n\n#### 122 多线程变量竞争引起的问题\n\n只要弄明白问题暴露的原因，叫问题出现还是不困难的。\n\n想象数据库的写入操作，一般需要耗费我们可以感知的时间。\n\n为了模拟这个写入动作，简化期间，我们只需要延长修改变量`a`的时间，问题很容易就会还原出来。\n\n```python\nimport threading\nimport time\n\n\na = 0\ndef add1():\n    global a    \n    tmp = a + 1\n    time.sleep(0.2) # 延时0.2秒，模拟写入所需时间\n    a = tmp\n    print('%s  adds a to 1: %d'%(threading.current_thread().getName(),a))\n    \nthreads = [threading.Thread(name='t%d'%(i,),target=add1) for i in range(10)]\n[t.start() for t in threads]\n```\n\n重新运行代码，只需一次，问题立马完全暴露，结果如下：\n\n```python\nt0  adds a to 1: 1\nt1  adds a to 1: 1\nt2  adds a to 1: 1\nt3  adds a to 1: 1\nt4  adds a to 1: 1\nt5  adds a to 1: 1\nt7  adds a to 1: 1\nt6  adds a to 1: 1\nt8  adds a to 1: 1\nt9  adds a to 1: 1\n```\n\n看到，10个线程全部运行后，`a`的值只相当于一个线程执行的结果。\n\n下面分析，为什么会出现上面的结果：\n\n这是一个很有说服力的例子，因为在修改a前，有0.2秒的休眠时间，某个线程延时后，CPU立即分配计算资源给其他线程。直到分配给所有线程后，根据结果反映出，0.2秒的休眠时长还没耗尽，这样每个线程get到的a值都是0，所以才出现上面的结果。\n\n\n\n以上最核心的三行代码：\n\n```python\ntmp = a + 1\ntime.sleep(0.2) # 延时0.2秒，模拟写入所需时间\na = tmp\n```\n\n<center>[上一个例子](121.md)    [下一个例子](123.md)</center>"
  },
  {
    "path": "md/123.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/11/1\n```\n\n#### 123 多线程锁\n\n知道问题出现的原因后，要想修复问题，也没那么复杂。\n\n通过python中提供的锁机制，某段代码只能单线程执行时，上锁，其他线程等待，直到释放锁后，其他线程再争锁，执行代码，释放锁，重复以上。\n\n创建一把锁`locka`:\n\n```python\nimport threading\nimport time\n\n\nlocka = threading.Lock()\n```\n\n通过 `locka.acquire()` 获得锁，通过`locka.release()`释放锁，它们之间的这些代码，只能单线程执行。\n\n```python\na = 0\ndef add1():\n    global a    \n    try:\n        locka.acquire() # 获得锁\n        tmp = a + 1\n        time.sleep(0.2) # 延时0.2秒，模拟写入所需时间\n        a = tmp\n    finally:\n        locka.release() # 释放锁\n    print('%s  adds a to 1: %d'%(threading.current_thread().getName(),a))\n    \nthreads = [threading.Thread(name='t%d'%(i,),target=add1) for i in range(10)]\n[t.start() for t in threads]\n```\n\n执行结果如下：\n\n```python\nt0  adds a to 1: 1\nt1  adds a to 1: 2\nt2  adds a to 1: 3\nt3  adds a to 1: 4\nt4  adds a to 1: 5\nt5  adds a to 1: 6\nt6  adds a to 1: 7\nt7  adds a to 1: 8\nt8  adds a to 1: 9\nt9  adds a to 1: 10\n```\n\n一切正常，其实这已经是单线程顺序执行了，就本例子而言，已经失去多线程的价值，并且还带来了因为线程创建开销，浪费时间的副作用。\n\n程序中只有一把锁，通过 `try...finally`还能确保不发生死锁。但是，当程序中启用多把锁，还是很容易发生死锁。\n\n注意使用场合，避免死锁，是我们在使用多线程开发时需要注意的一些问题。\n\n<center>[上一个例子](122.md)    [下一个例子](124.md)</center>\n"
  },
  {
    "path": "md/124.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/11/16\n```\n\n**124 时间转数组及常用格式**\n\n```python\nIn [68]: str_to_struct = time.strptime(format_time,'%Y-%m-%d %H:%M:%S')\n\nIn [69]: str_to_struct\nOut[69]: time.struct_time(tm_year=2020, tm_mon=2, tm_mday=22, tm_hour=11, tm_min=19, tm_sec=19, tm_wday=5, tm_yday=53, tm_isdst=-1)\n```\n\n最后再记住常用字符串格式\n\n**常用字符串格式**\n\n%m：月\n\n%M: 分钟\n\n```markdown\n    %Y  Year with century as a decimal number.\n    %m  Month as a decimal number [01,12].\n    %d  Day of the month as a decimal number [01,31].\n    %H  Hour (24-hour clock) as a decimal number [00,23].\n    %M  Minute as a decimal number [00,59].\n    %S  Second as a decimal number [00,61].\n    %z  Time zone offset from UTC.\n    %a  Locale's abbreviated weekday name.\n    %A  Locale's full weekday name.\n    %b  Locale's abbreviated month name.\n```\n\n<center>[上一个例子](123.md)    [下一个例子](125.md)</center>"
  },
  {
    "path": "md/125.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/11/14\n```\n\n#### 125 寻找第n次出现位置\n\n```python\ndef search_n(s, c, n):\n    size = 0\n    for i, x in enumerate(s):\n        if x == c:\n            size += 1\n        if size == n:\n            return i\n    return -1\n\n\n\nprint(search_n(\"fdasadfadf\", \"a\", 3))# 结果为7，正确\nprint(search_n(\"fdasadfadf\", \"a\", 30))# 结果为-1，正确\n```\n\n<center>[上一个例子](124.md)    [下一个例子](126.md)</center>"
  },
  {
    "path": "md/126.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/11/23\n```\n\n#### 126 斐波那契数列前n项\n\n```python\ndef fibonacci(n):\n    a, b = 1, 1\n    for _ in range(n):\n        yield a\n        a, b = b, a + b\n\n\nlist(fibonacci(5))  # [1, 1, 2, 3, 5]\n```\n\n<center>[上一个例子](125.md)    [下一个例子](127.md)</center>"
  },
  {
    "path": "md/127.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/11/30\n```\n\n#### 127 找出所有重复元素\n\n```python\nfrom collections import Counter\n\n\ndef find_all_duplicates(lst):\n    c = Counter(lst)\n    return list(filter(lambda k: c[k] > 1, c))\n\n\nfind_all_duplicates([1, 2, 2, 3, 3, 3])  # [2,3]\n```\n\n<center>[上一个例子](126.md)    [下一个例子](128.md)</center>"
  },
  {
    "path": "md/128.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/12/1\n```\n\n#### 128 联合统计次数\nCounter对象间可以做数学运算\n\n```python\nfrom collections import Counter\na = ['apple', 'orange', 'computer', 'orange']\nb = ['computer', 'orange']\n\nca = Counter(a)\ncb = Counter(b)\n#Counter对象间可以做数学运算\nca + cb  # Counter({'orange': 3, 'computer': 2, 'apple': 1})\n\n\n# 进一步抽象，实现多个列表内元素的个数统计\n\n\ndef sumc(*c):\n    if (len(c) < 1):\n        return\n    mapc = map(Counter, c)\n    s = Counter([])\n    for ic in mapc: # ic 是一个Counter对象\n        s += ic\n    return s\n\n\n#Counter({'orange': 3, 'computer': 3, 'apple': 1, 'abc': 1, 'face': 1})\nsumc(a, b, ['abc'], ['face', 'computer'])\n\n```\n\n<center>[上一个例子](127.md)    [下一个例子](129.md)</center>"
  },
  {
    "path": "md/129.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/12/3\n```\n\n#### 129 groupby单字段分组\n\n天气记录：\n\n```python\na = [{'date': '2019-12-15', 'weather': 'cloud'},\n {'date': '2019-12-13', 'weather': 'sunny'},\n {'date': '2019-12-14', 'weather': 'cloud'}]\n```\n\n按照天气字段`weather`分组汇总：\n\n```python\nfrom itertools import groupby\nfor k, items in  groupby(a,key=lambda x:x['weather']):\n     print(k)\n```\n\n输出结果看出，分组失败！原因：分组前必须按照分组字段`排序`，这个很坑~\n\n```python\ncloud\nsunny\ncloud\n```\n\n修改代码：\n\n```python\na.sort(key=lambda x: x['weather'])\nfor k, items in  groupby(a,key=lambda x:x['weather']):\n     print(k)\n     for i in items:\n         print(i)\n```\n\n输出结果：\n\n```python\ncloud\n{'date': '2019-12-15', 'weather': 'cloud'}\n{'date': '2019-12-14', 'weather': 'cloud'}\nsunny\n{'date': '2019-12-13', 'weather': 'sunny'}\n```\n\n<center>[上一个例子](128.md)    [下一个例子](130.md)</center>"
  },
  {
    "path": "md/13.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/15\n```\n\n#### 13 链式比较\n\nPython支持这种连续不等比较，写起来更方便\n\n```python\ni = 3\nprint(1 < i < 3)  # False\nprint(1 < i <= 3)  # True\n```\n\n\n<center>[上一个例子](12.md)    [下一个例子](14.md)</center>\n"
  },
  {
    "path": "md/130.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/12/8\n```\n\n#### 130 groupby多字段分组\n\n`itemgetter`是一个类，`itemgetter('weather')`返回一个可调用的对象，它的参数可有多个：\n\n```python\nfrom operator import itemgetter\nfrom itertools import groupby\n\na.sort(key=itemgetter('weather', 'date'))\nfor k, items in groupby(a, key=itemgetter('weather')):\n     print(k)\n     for i in items:\n         print(i)\n```\n\n结果如下，使用`weather`和`date`两个字段排序`a`，\n\n```python\ncloud\n{'date': '2019-12-14', 'weather': 'cloud'}\n{'date': '2019-12-15', 'weather': 'cloud'}\nsunny\n{'date': '2019-12-13', 'weather': 'sunny'}\n```\n\n注意这个结果与上面结果有些微妙不同，这个更多是我们想看到和使用更多的。\n\n<center>[上一个例子](129.md)    [下一个例子](131.md)</center>"
  },
  {
    "path": "md/131.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/12/19\n```\n\n#### 131 itemgetter和key函数\n\n注意到`sort`和`groupby`所用的`key`函数，除了`lambda`写法外，还有一种简写，就是使用`itemgetter`：\n\n```python\na = [{'date': '2019-12-15', 'weather': 'cloud'},\n {'date': '2019-12-13', 'weather': 'sunny'},\n {'date': '2019-12-14', 'weather': 'cloud'}]\nfrom operator import itemgetter\nfrom itertools import groupby\n\na.sort(key=itemgetter('weather'))\nfor k, items in groupby(a, key=itemgetter('weather')):\n     print(k)\n     for i in items:\n         print(i)\n```\n\n结果：\n\n```python\ncloud\n{'date': '2019-12-15', 'weather': 'cloud'}\n{'date': '2019-12-14', 'weather': 'cloud'}\nsunny\n{'date': '2019-12-13', 'weather': 'sunny'}\n```\n\n<center>[上一个例子](130.md)    [下一个例子](132.md)</center>"
  },
  {
    "path": "md/132.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/12/30\n```\n\n#### 132 sum函数计算和聚合同时做\n\nPython中的聚合类函数`sum`,`min`,`max`第一个参数是`iterable`类型，一般使用方法如下：\n\n```python\na = [4,2,5,1]\nsum([i+1 for i in a]) # 16\n```\n\n使用列表生成式`[i+1 for i in a]`创建一个长度与`a`一行的临时列表，这步完成后，再做`sum`聚合。\n\n试想如果你的数组`a`长度十百万级，再创建一个这样的临时列表就很不划算，最好是一边算一边聚合，稍改动为如下：\n\n```python\na = [4,2,5,1]\nsum(i+1 for i in a) # 16\n```\n\n此时`i+1 for i in a`是`(i+1 for i in a)`的简写，得到一个生成器(`generator`)对象，如下所示：\n\n```python\nIn [8]:(i+1 for i in a)\nOUT [8]:<generator object <genexpr> at 0x000002AC7FFA8CF0>\n```\n\n生成器每迭代一步吐出(`yield`)一个元素并计算和聚合后，进入下一次迭代，直到终点。\n\n<center>[上一个例子](131.md)    [下一个例子](133.md)</center>"
  },
  {
    "path": "md/133.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2020/1/1\n```\n\n#### 133 获得某天后的1~n天\n\n```python\nimport calendar\nfrom datetime import date,datetime\n\ndef getEverydaySince(year,month,day,n=10):\n    i = 0\n    _, days = calendar.monthrange(year, month)\n    while i < n: \n        d = date(year,month,day)    \n        if day == days:\n            month,day = month+1,0\n            _, days = calendar.monthrange(year, month)\n            if month == 13:\n                year,month = year+1,1\n                _, days = calendar.monthrange(year, month)\n        yield d\n        day += 1\n        i += 1\n```\n\n测试结果：\n\n```markdown\nIn [3]: for day in getEverydaySince(2020,2,1): \n   ...:     print(day)                                                                      \n2020-02-01\n2020-02-02\n2020-02-03\n2020-02-04\n2020-02-05\n2020-02-06\n2020-02-07\n2020-02-08\n2020-02-09\n2020-02-10\n```\n\n\n\n<center>[上一个例子](132.md)    [下一个例子](134.md)</center>"
  },
  {
    "path": "md/134.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag yield generator\n@version \n@date 2020/02/01\n```\n\n#### 134 list分组(生成器版)\n\n```python\nfrom math import ceil\n\ndef divide_iter(lst, n):\n    if n <= 0:\n        yield lst\n        return\n    i, div = 0, ceil(len(lst) / n)\n    while i < n:\n        yield lst[i * div: (i + 1) * div]\n        i += 1\n\nlist(divide_iter([1, 2, 3, 4, 5], 0))  # [[1, 2, 3, 4, 5]]\nlist(divide_iter([1, 2, 3, 4, 5], 2))  # [[1, 2, 3], [4, 5]]\n```\n\n<center>[上一个例子](133.md)    [下一个例子](135.md)</center>"
  },
  {
    "path": "md/135.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/02\n```\n\n#### 135 列表全展开(生成器版)\n```python\n#多层列表展开成单层列表\na=[1,2,[3,4,[5,6],7],8,[\"python\",6],9]\ndef function(lst):\n    for i in lst:\n        if type(i)==list:\n            yield from function(i)\n        else:\n            yield i\nprint(list(function(a))) # [1, 2, 3, 4, 5, 6, 7, 8, 'python', 6, 9]\n```\n\n<center>[上一个例子](134.md)    [下一个例子](136.md)</center>"
  },
  {
    "path": "md/136.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag decorator\n@version \n@date 2020/02/03\n```\n\n#### 136 测试函数运行时间的装饰器\n```python\n#测试函数执行时间的装饰器示例\nimport time\ndef timing_func(fn):\n    def wrapper():\n        start=time.time()\n        fn()   #执行传入的fn参数\n        stop=time.time()\n        return (stop-start)\n    return wrapper\n```\n\n使用装饰器：\n\n```python\n@timing_func\ndef test_list_append():\n    lst=[]\n    for i in range(0,100000):\n        lst.append(i)  \n@timing_func\ndef test_list_compre():\n    [i for i in range(0,100000)]  #列表生成式\n    \na=test_list_append()\nc=test_list_compre()\n\nprint(\"test list append time:\",a)\nprint(\"test list comprehension time:\",c)\nprint(\"append/compre:\",round(a/c,3))\n\n#test list append time: 0.0219423770904541\n#test list comprehension time: 0.007980823516845703\n#append/compre: 2.749\n```\n\n\n\n<center>[上一个例子](135.md)    [下一个例子](137.md)</center>"
  },
  {
    "path": "md/137.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/04\n```\n\n#### 137 统计异常次数装饰器\n\n\n写一个装饰器，统计某个异常重复出现指定次数时，经历的时长。\n\n```python\nimport time\nimport math\n\n\ndef excepter(f):\n    i = 0\n    t1 = time.time()\n    def wrapper(): \n        try:\n            f()\n        except Exception as e:\n            nonlocal i\n            i += 1\n            print(f'{e.args[0]}: {i}')\n            t2 = time.time()\n            if i == n:\n                print(f'spending time:{round(t2-t1,2)}')\n    return wrapper\n\n```\n\n关键词`nonlocal`常用于函数嵌套中，声明变量i为非局部变量；\n\n如果不声明，`i+=1`表明`i`为函数`wrapper`内的局部变量，因为在`i+=1`引用(reference)时,`i`未被声明，所以会报`unreferenced variable`的错误。\n\n使用创建的装饰函数`excepter`, `n`是异常出现的次数。\n\n共测试了两类常见的异常：`被零除`和`数组越界`。\n\n```python\nn = 10 # except count\n\n@excepter\ndef divide_zero_except():\n    time.sleep(0.1)\n    j = 1/(40-20*2)\n\n# test zero divived except\nfor _ in range(n):\n    divide_zero_except()\n\n\n@excepter\ndef outof_range_except():\n    a = [1,3,5]\n    time.sleep(0.1)\n    print(a[3])\n# test out of range except\nfor _ in range(n):\n    outof_range_except()\n\n```\n\n打印出来的结果如下：\n\n```python\ndivision by zero: 1\ndivision by zero: 2\ndivision by zero: 3\ndivision by zero: 4\ndivision by zero: 5\ndivision by zero: 6\ndivision by zero: 7\ndivision by zero: 8\ndivision by zero: 9\ndivision by zero: 10\nspending time:1.01\nlist index out of range: 1\nlist index out of range: 2\nlist index out of range: 3\nlist index out of range: 4\nlist index out of range: 5\nlist index out of range: 6\nlist index out of range: 7\nlist index out of range: 8\nlist index out of range: 9\nlist index out of range: 10\nspending time:1.01\n```\n\n\n#### \n\n<center>[上一个例子](136.md)    [下一个例子](138.md)</center>"
  },
  {
    "path": "md/138.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/05\n```\n\n#### 138 装饰器通俗理解\n\n再看一个装饰器：\n\n```python\ndef call_print(f):\n  def g():\n    print('you\\'re calling %s function'%(f.__name__,))\n  return g\n```\n\n使用`call_print`装饰器：\n\n```python\n@call_print\ndef myfun():\n  pass\n \n@call_print\ndef myfun2():\n  pass\n```\n\nmyfun()后返回：\n\n```python\nIn [27]: myfun()\nyou're calling myfun function\n\nIn [28]: myfun2()\nyou're calling myfun2 function\n```\n\n**使用call_print**\n\n你看，`@call_print`放置在任何一个新定义的函数上面，都会默认输出一行，你正在调用这个函数的名。\n\n这是为什么呢？注意观察新定义的`call_print`函数(加上@后便是装饰器):\n\n```python\ndef call_print(f):\n  def g():\n    print('you\\'re calling %s function'%(f.__name__,))\n  return g\n```\n\n它必须接受一个函数`f`，然后返回另外一个函数`g`.\n\n**装饰器本质**\n\n本质上，它与下面的调用方式效果是等效的：\n\n```\ndef myfun():\n  pass\n\ndef myfun2():\n  pass\n  \ndef call_print(f):\n  def g():\n    print('you\\'re calling %s function'%(f.__name__,))\n  return g\n```\n\n下面是最重要的代码：\n\n```\nmyfun = call_print(myfun)\nmyfun2 = call_print(myfun2)\n```\n\n大家看明白吗？也就是call_print(myfun)后不是返回一个函数吗，然后再赋值给myfun.\n\n再次调用myfun, myfun2时，效果是这样的：\n\n```python\nIn [32]: myfun()\nyou're calling myfun function\n\nIn [33]: myfun2()\nyou're calling myfun2 function\n```\n\n你看，这与装饰器的实现效果是一模一样的。装饰器的写法可能更加直观些，所以不用显示的这样赋值：`myfun = call_print(myfun)`，`myfun2 = call_print(myfun2)`，但是装饰器的这种封装，猛一看，有些不好理解。\n\n<center>[上一个例子](137.md)    [下一个例子](139.md)</center>"
  },
  {
    "path": "md/139.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/06\n```\n#### 139 定制递减迭代器\n\n```python\n#编写一个迭代器，通过循环语句，实现对某个正整数的依次递减1，直到0.\nclass Descend(Iterator):\n    def __init__(self,N):\n        self.N=N\n        self.a=0\n    def __iter__(self):\n        return self \n    def __next__(self):\n        while self.a<self.N:\n            self.N-=1\n            return self.N\n        raise StopIteration\n    \ndescend_iter=Descend(10)\nprint(list(descend_iter))\n[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]\n```\n\n核心要点：\n\n1 `__nex__ `名字不能变，实现定制的迭代逻辑\n\n2 `raise StopIteration`：通过 raise 中断程序，必须这样写\n    \n\n<center>[上一个例子](138.md)    [下一个例子](140.md)</center>"
  },
  {
    "path": "md/14.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/15\n```\n\n#### 14  字符串转字节　　\n\n字符串转换为字节类型\n\n```python\nIn [12]: s = \"apple\"                                                            \n\nIn [13]: a = bytes(s,encoding='utf-8')   \nIn [14] a \nOut[14]: b'apple'\n\n# 转化后a变为字节序列，bytes类型，\n# 并且每个字符都被转化为数值，如下所示\nIn [15]: for i in a: \n    ...:     print(i)                                                                       \n97\n112\n112\n108\n101\n```\n\n\n<center>[上一个例子](13.md)    [下一个例子](15.md)</center>\n"
  },
  {
    "path": "md/140.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/07\n```\n\t\t     \n#### 140 turtle绘制奥运五环图\n\nturtle绘图的函数非常好用，基本看到函数名字，就能知道它的含义，下面使用turtle，仅用15行代码来绘制奥运五环图。\n\n1 导入库\n\n```python\nimport turtle as p\n```\n\n2 定义画圆函数\n\n```python\ndef drawCircle(x,y,c='red'):\n    p.pu()# 抬起画笔\n    p.goto(x,y) # 绘制圆的起始位置\n    p.pd()# 放下画笔\n    p.color(c)# 绘制c色圆环\n    p.circle(30,360) #绘制圆：半径，角度\n```\n\n3 画笔基本设置\n\n```python\np = turtle\np.pensize(3) # 画笔尺寸设置3\n```\n\n4 绘制五环图\n\n调用画圆函数\n\n```python\ndrawCircle(0,0,'blue')\ndrawCircle(60,0,'black')\ndrawCircle(120,0,'red')\ndrawCircle(90,-30,'green')\ndrawCircle(30,-30,'yellow')    \n\np.done()\n```\n\n<center>[上一个例子](139.md)    [下一个例子](141.md)</center>"
  },
  {
    "path": "md/141.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/08\n```\n\t\t     \n#### 141 turtle绘制漫天雪花\n\n\n导入模块\n\n导入 `turtle`库和 python的 `random`\n\n```python\nimport turtle as p\nimport random\n```\n\n绘制雪花\n\n```python\ndef snow(snow_count):\n    p.hideturtle()\n    p.speed(500)\n    p.pensize(2)\n    for i in range(snow_count):\n        r = random.random()\n        g = random.random()\n        b = random.random()\n        p.pencolor(r, g, b)\n        p.pu()\n        p.goto(random.randint(-350, 350), random.randint(1, 270))\n        p.pd()\n        dens = random.randint(8, 12)\n        snowsize = random.randint(10, 14)\n        for _ in range(dens):\n            p.forward(snowsize)  # 向当前画笔方向移动snowsize像素长度\n            p.backward(snowsize)  # 向当前画笔相反方向移动snowsize像素长度\n            p.right(360 / dens)  # 顺时针移动360 / dens度\n\n```\n\n绘制地面\n\n```python\ndef ground(ground_line_count):\n    p.hideturtle()\n    p.speed(500)\n    for i in range(ground_line_count):\n        p.pensize(random.randint(5, 10))\n        x = random.randint(-400, 350)\n        y = random.randint(-280, -1)\n        r = -y / 280\n        g = -y / 280\n        b = -y / 280\n        p.pencolor(r, g, b)\n        p.penup()  # 抬起画笔\n        p.goto(x, y)  # 让画笔移动到此位置\n        p.pendown()  # 放下画笔\n        p.forward(random.randint(40, 100))  # 眼当前画笔方向向前移动40~100距离\n```\n\n主函数\n\n```python\ndef main():\n    p.setup(800, 600, 0, 0)\n    # p.tracer(False)\n    p.bgcolor(\"black\")\n    snow(30)\n    ground(30)\n    # p.tracer(True)\n    p.mainloop()\n\nmain()\n```\n\n<center>[上一个例子](140.md)    [下一个例子](142.md)</center>"
  },
  {
    "path": "md/142.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/09\n```\n\n```python\nimport hashlib\nimport pandas as pd\nfrom wordcloud import WordCloud\n```\n\n```python\ngeo_data=pd.read_excel(r\"../data/geo_data.xlsx\")\nprint(geo_data)\n# 0     深圳\n# 1     深圳\n# 2     深圳\n# 3     深圳\n# 4     深圳\n# 5     深圳\n# 6     深圳\n# 7     广州\n# 8     广州\n# 9     广州\n```\n\n```python\n#筛选出非空列表值\nwords = ','.join(x for x in geo_data['city'] if x != []) \nwc = WordCloud(\n    background_color=\"green\", #背景颜色\"green\"绿色\n    max_words=100, #显示最大词数\n    font_path='./fonts/simhei.ttf', #显示中文\n    min_font_size=5,\n    max_font_size=100,\n    width=500  #图幅宽度\n    )\n```\n\n```python\nx = wc.generate(words)\nx.to_file('../data/geo_data.png') \n```\n\n<center>[上一个例子](141.md)    [下一个例子](143.md)</center>"
  },
  {
    "path": "md/143.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/10\n```\n\n```python\n#柱状图+折线图\nimport plotly.graph_objects as go\nfig = go.Figure()\nfig.add_trace(\n    go.Scatter(\n        x=[0, 1, 2, 3, 4, 5],\n        y=[1.5, 1, 1.3, 0.7, 0.8, 0.9]\n    ))\nfig.add_trace(\n    go.Bar(\n        x=[0, 1, 2, 3, 4, 5],\n        y=[2, 0.5, 0.7, -1.2, 0.3, 0.4]\n    ))\nfig.show()\n```    \n\n<center>[上一个例子](142.md)    [下一个例子](144.md)</center>"
  },
  {
    "path": "md/144.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/11\n```\n\n```python\n# 导入库\nimport seaborn as sns\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n# 生成数据集\ndata = np.random.random((6,6))\nnp.fill_diagonal(data,np.ones(6))\nfeatures = [\"prop1\",\"prop2\",\"prop3\",\"prop4\",\"prop5\", \"prop6\"]\ndata = pd.DataFrame(data, index = features, columns=features)\nprint(data)\n# 绘制热力图\nheatmap_plot = sns.heatmap(data, center=0, cmap='gist_rainbow')\nplt.show()\n```    \n\n<center>[上一个例子](143.md)    [下一个例子](145.md)</center>"
  },
  {
    "path": "md/145.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/12\n```\n\n```python\nfrom pyecharts import charts\n\n# 仪表盘\ngauge = charts.Gauge()\ngauge.add('Python小例子', [('Python机器学习', 30), ('Python基础', 70.),\n                        ('Python正则', 90)])\ngauge.render(path=\"./data/仪表盘.html\")\nprint('ok')\n```  \n\n仪表盘中共展示三项，每项的比例为30%,70%,90%，如下图默认名称显示第一项：Python机器学习，完成比例为30%\n\n<center>[上一个例子](144.md)    [下一个例子](146.md)</center>"
  },
  {
    "path": "md/146.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/13\n```\n\n```python\nfrom pyecharts import options as opts\nfrom pyecharts.charts import Funnel, Page\nfrom random import randint\n\ndef funnel_base() -> Funnel:\n  c = (\n    Funnel()\n    .add(\"豪车\", [list(z) for z in zip(['宝马', '法拉利', '奔驰', '奥迪', '大众', '丰田', '特斯拉'],\n                 [randint(1, 20) for _ in range(7)])])\n    .set_global_opts(title_opts=opts.TitleOpts(title=\"豪车漏斗图\"))\n  )\n  return c\nfunnel_base().render('./img/car_fnnel.html')  \n```\n\n<center>[上一个例子](145.md)    [下一个例子](147.md)</center>"
  },
  {
    "path": "md/147.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/14\n```\n\n```python\nfrom pyecharts import options as opts\nfrom pyecharts.charts import Liquid, Page\nfrom pyecharts.globals import SymbolType\n\ndef liquid() -> Liquid:\n    c = (\n        Liquid()\n        .add(\"lq\", [0.67, 0.30, 0.15])\n        .set_global_opts(title_opts=opts.TitleOpts(title=\"Liquid\"))\n    )\n    return c\n\nliquid().render('./img/liquid.html')\n```    \n\n<center>[上一个例子](146.md)    [下一个例子](148.md)</center>"
  },
  {
    "path": "md/148.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/15\n```\n\n```python\nfrom pyecharts import options as opts\nfrom pyecharts.charts import Pie\nfrom random import randint\n\ndef pie_base() -> Pie:\n    c = (\n        Pie()\n        .add(\"\", [list(z) for z in zip(['宝马', '法拉利', '奔驰', '奥迪', '大众', '丰田', '特斯拉'],\n                                       [randint(1, 20) for _ in range(7)])])\n        .set_global_opts(title_opts=opts.TitleOpts(title=\"Pie-基本示例\"))\n        .set_series_opts(label_opts=opts.LabelOpts(formatter=\"{b}: {c}\"))\n    )\n    return c\n\npie_base().render('./img/pie_pyecharts.html')   \n```\n\n<center>[上一个例子](147.md)    [下一个例子](149.md)</center>"
  },
  {
    "path": "md/149.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/16\n```\n\n```python\nimport random\nfrom pyecharts import options as opts\nfrom pyecharts.charts import Page, Polar\n\ndef polar_scatter0() -> Polar:\n    data = [(alpha, random.randint(1, 100)) for alpha in range(101)] # r = random.randint(1, 100)\n    print(data)\n    c = (\n        Polar()\n        .add(\"\", data, type_=\"bar\", label_opts=opts.LabelOpts(is_show=False))\n        .set_global_opts(title_opts=opts.TitleOpts(title=\"Polar\"))\n    )\n    return c\n\npolar_scatter0().render('./img/polar.html')\n```    \n\n<center>[上一个例子](148.md)    [下一个例子](150.md)</center>"
  },
  {
    "path": "md/15.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/15\n```\n\n#### 15 任意对象转为字符串　　\n\n```python\n                                                              \n\nIn [1]: str(100)                                                                 \nOut[1]: '100'\n\nIn [2]: str([3,2,10])                                                           \nOut[2]: '[3, 2, 10]'\n\nIn [3]: str({'a':1, 'b':10})                                                    \nOut[3]: \"{'a': 1, 'b': 10}\"\n\nIn [11]: from collections import defaultdict                                    \nIn [12]: dd = defaultdict(int)                                                  \n\nIn [14]: for i in [1,3,2,2,3,3]: \n    ...:     dd[i] += 1 \n    ...:                                                                        \n\nIn [15]: dd                                                                     \nOut[15]: defaultdict(int, {1: 1, 3: 3, 2: 2})\n\nIn [16]: str(dd)                                                                \nOut[16]: \"defaultdict(<class 'int'>, {1: 1, 3: 3, 2: 2})\"\n\n```\n\n<center>[上一个例子](14.md)    [下一个例子](16.md)</center>\n"
  },
  {
    "path": "md/150.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/17\n```\n\n```python\nfrom pyecharts import options as opts\nfrom pyecharts.charts import Page, WordCloud\nfrom pyecharts.globals import SymbolType\n\nwords = [\n    (\"Python\", 100),\n    (\"C++\", 80),\n    (\"Java\", 95),\n    (\"R\", 50),\n    (\"JavaScript\", 79),\n    (\"C\", 65)\n]\n\ndef wordcloud() -> WordCloud:\n    c = (\n        WordCloud()\n        # word_size_range: 单词字体大小范围\n        .add(\"\", words, word_size_range=[20, 100], shape='cardioid')\n        .set_global_opts(title_opts=opts.TitleOpts(title=\"WordCloud\"))\n    )\n    return c\n\nwordcloud().render('./img/wordcloud.html')     \n```\n\n<center>[上一个例子](149.md)    [下一个例子](151.md)</center>"
  },
  {
    "path": "md/151.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/18\n```\n\n```python\nimport random\nfrom pyecharts import options as opts\nfrom pyecharts.charts import HeatMap\n\ndef heatmap_car() -> HeatMap:\n    x = ['宝马', '法拉利', '奔驰', '奥迪', '大众', '丰田', '特斯拉']\n    y = ['中国','日本','南非','澳大利亚','阿根廷','阿尔及利亚','法国','意大利','加拿大']\n    value = [[i, j, random.randint(0, 100)]\n             for i in range(len(x)) for j in range(len(y))]\n    c = (\n        HeatMap()\n        .add_xaxis(x)\n        .add_yaxis(\"销量\", y, value)\n        .set_global_opts(\n            title_opts=opts.TitleOpts(title=\"HeatMap\"),\n            visualmap_opts=opts.VisualMapOpts(),\n        )\n    )\n    return c\n\nheatmap_car().render('./img/heatmap_pyecharts.html') \n```\n\n热力图描述的实际是三维关系，x轴表示车型，y轴表示国家，每个色块的颜色值代表销量，颜色刻度尺显示在左下角，颜色越红表示销量越大。\n\n<center>[上一个例子](150.md)    [下一个例子](152.md)</center>"
  },
  {
    "path": "md/152.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/19\n```\n\n### matplotlib绘制动画\n\nmatplotlib是python中最经典的绘图包，里面animation模块能绘制动画。\n\n首先导入小例子使用的模块：\n\n```python\nfrom matplotlib import pyplot as plt\nfrom matplotlib import animation\nfrom random import randint, random\n```\n\n生成数据，frames_count是帧的个数，data_count每个帧的柱子个数\n\n```python \nclass Data:\n    data_count = 32\n    frames_count = 2\n\n    def __init__(self, value):\n        self.value = value\n        self.color = (0.5, random(), random()) #rgb\n\n    # 造数据\n    @classmethod\n    def create(cls):\n        return [[Data(randint(1, cls.data_count)) for _ in range(cls.data_count)]\n                for frame_i in range(cls.frames_count)]\n\n```\n\n绘制动画：animation.FuncAnimation函数的回调函数的参数fi表示第几帧，注意要调用axs.cla()清除上一帧。\n\n```python\ndef draw_chart():\n    fig = plt.figure(1, figsize=(16, 9))\n    axs = fig.add_subplot(111)\n    axs.set_xticks([])\n    axs.set_yticks([])\n\n    # 生成数据\n    frames = Data.create()\n\n    def animate(fi):\n        axs.cla()  # clear last frame\n        axs.set_xticks([])\n        axs.set_yticks([])\n        return axs.bar(list(range(Data.data_count)),        # X\n                       [d.value for d in frames[fi]],       # Y\n                       1,                                   # width\n                       color=[d.color for d in frames[fi]]  # color\n                       )\n    # 动画展示\n    anim = animation.FuncAnimation(fig, animate, frames=len(frames))\n    plt.show()\n```\n\n```python\ndraw_chart()\n179     \n```\n\n<center>[上一个例子](151.md)    [下一个例子](153.md)</center>"
  },
  {
    "path": "md/153.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/20\n```\n\n### 学会画 pairplot 图\nseaborn 绘图库，基于 matplotlib 开发，提供更高层绘图接口。\n\n学习使用 seaborn 绘制 pairplot 图\n\npairplot 图能直观的反映出两两特征间的关系，帮助我们对数据集建立初步印象，更好的完成分类和聚类任务。\n\n使用 skearn 导入经典的 Iris 数据集，共有 150 条记录，4 个特征，target 有三种不同值。如下所示：\n\n```markdown\n     sepal_length  sepal_width  petal_length  petal_width    species\n0             5.1          3.5           1.4          0.2     setosa\n1             4.9          3.0           1.4          0.2     setosa\n2             4.7          3.2           1.3          0.2     setosa\n3             4.6          3.1           1.5          0.2     setosa\n4             5.0          3.6           1.4          0.2     setosa\n..            ...          ...           ...          ...        ...\n145           6.7          3.0           5.2          2.3  virginica\n146           6.3          2.5           5.0          1.9  virginica\n147           6.5          3.0           5.2          2.0  virginica\n148           6.2          3.4           5.4          2.3  virginica\n149           5.9          3.0           5.1          1.8  virginica\n```\n\n使用 seaborn 绘制 sepal_length, petal_length 两个特征间的关系矩阵：\n\n```python\nfrom sklearn.datasets import load_iris\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom sklearn import tree\n\nsns.set(style=\"ticks\")\n\ndf02 = df.iloc[:,[0,2,4]] # 选择一对特征\nsns.pairplot(df02)\nplt.show()\n```\n\n\n设置颜色多显：\n```python\nsns.pairplot(df02, hue=\"species\")\nplt.show()\n```\n\n绘制所有特征散点矩阵：\n```python\nsns.pairplot(df, hue=\"species\")\nplt.show()\n```\n   \n\n<center>[上一个例子](152.md)    [下一个例子](154.md)</center>"
  },
  {
    "path": "md/154.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/21\n```\n\n### 含单个元素的元组\nPython中有些函数的参数类型为元组，其内有1个元素，这样创建是错误的：\n```python\nc = (5) # NO!\n```\n\n它实际创建一个整型元素5，必须要在元素后加一个逗号:\n\n```python\nc = (5,) # YES!\n186   \n\n```\n\n<center>[上一个例子](153.md)    [下一个例子](155.md)</center>"
  },
  {
    "path": "md/155.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/22\n```\n\n### 默认参数设为空\n\n含有默认参数的函数，如果类型为容器，且设置为空：\n\n```python\ndef f(a,b=[]):  # NO!\n    print(b)\n    return b\n```\n\n```python \nret = f(1)\nret.append(1)\nret.append(2)\n```\n\n# 当再调用f(1)时，预计打印为 []\nf(1)\n# 但是却为 [1,2]\n\n这是可变类型的默认参数之坑，请务必设置此类默认参数为None：\n\ndef f(a,b=None): # YES!\n    pass\n\n<center>[上一个例子](154.md)    [下一个例子](156.md)</center>"
  },
  {
    "path": "md/156.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/23\n```\n\n### 共享变量未绑定之坑\n有时想要多个函数共享一个全局变量，但却在某个函数内试图修改它为局部变量：\n\n```python\ni = 1\ndef f():\n    i+=1 #NO!\n    \ndef g():\n    print(i)\n\n```\n\n应该在f函数内显示声明i为global变量：\n\n```python \ni = 1\ndef f():\n    global i # YES!\n    i+=1\n```\n\n\n\n<center>[上一个例子](155.md)    [下一个例子](157.md)</center>"
  },
  {
    "path": "md/157.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/24\n```\n\n### lambda自由参数之坑\n排序和分组的key函数常使用lambda，表达更加简洁，但是有个坑新手容易掉进去：\n```python\na = [lambda x: x+i for i in range(3)] # NO!\nfor f in a:\n    print(f(1))\n# 你可能期望输出：1,2,3\n```\n\n但是实际却输出: 3,3,3. 定义lambda使用的i被称为自由参数，它只在调用lambda函数时，值才被真正确定下来，这就犹如下面打印出2，你肯定确信无疑吧。\n\n```python \na = 0\na = 1\na = 2\ndef f(a):\n    print(a)\n```\n\n正确做法是转化自由参数为lambda函数的默认参数：\n```python\na = [lambda x,i=i: x+i for i in range(3)] # YES!    \n```\n\n<center>[上一个例子](156.md)    [下一个例子](158.md)</center>"
  },
  {
    "path": "md/158.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/25\n```\n\n### 各种参数使用之坑\n\nPython强大多变，原因之一在于函数参数类型的多样化。方便的同时，也为使用者带来更多的约束规则。如果不了解这些规则，调用函数时，可能会出现如下一些语法异常：\n\n*(1) SyntaxError: positional argument follows keyword argument*\n\n\n*(2) TypeError: f() missing 1 required keyword-only argument: 'b'*\n\n\n*(3) SyntaxError: keyword argument repeated*\n\n*(4) TypeError: f() missing 1 required positional argument: 'b'*\n\n*(5) TypeError: f() got an unexpected keyword argument 'a'*\n\n*(6) TypeError: f() takes 0 positional arguments but 1 was given*\n\n\n总结主要的参数使用规则\n\n位置参数\n\n`位置参数`的定义：`函数调用`时根据函数定义的参数位（形参）置来传递参数，是最常见的参数类型。\n\n```python\ndef f(a):\n  return a\n\nf(1) # 位置参数 \n```\n位置参数不能缺少：\n```python\ndef f(a,b):\n  pass\n\nf(1) # TypeError: f() missing 1 required positional argument: 'b'\n```\n\n**规则1：位置参数必须一一对应，缺一不可**\n\n关键字参数\n\n在函数调用时，通过‘键--值’方式为函数形参传值，不用按照位置为函数形参传值。\n\n```python\ndef f(a):\n  print(f'a:{a}')\n```\n这么调用，`a`就是关键字参数：\n```python\nf(a=1)\n```\n但是下面调用就不OK:\n```python\nf(a=1,20.) # SyntaxError: positional argument follows keyword argument\n```\n\n**规则2：关键字参数必须在位置参数右边**\n\n\n下面调用也不OK:\n```python\nf(1,width=20.,width=30.) #SyntaxError: keyword argument repeated\n\n```\n\n**规则3：对同一个形参不能重复传值**\n\n\n默认参数\n\n在定义函数时，可以为形参提供默认值。对于有默认值的形参，调用函数时如果为该参数传值，则使用传入的值，否则使用默认值。如下`b`是默认参数：\n```python\ndef f(a,b=1):\n  print(f'a:{a}, b:{b}')\n\n```\n\n\n**规则4：无论是函数的定义还是调用，默认参数的定义应该在位置形参右面**\n\n只在定义时赋值一次；默认参数通常应该定义成不可变类型\n\n\n可变位置参数\n\n如下定义的参数a为可变位置参数：\n```python\ndef f(*a):\n  print(a)\n```\n调用方法：\n```python\nf(1) #打印结果为元组： (1,)\nf(1,2,3) #打印结果：(1, 2, 3)\n```\n\n但是，不能这么调用：\n```python\nf(a=1) # TypeError: f() got an unexpected keyword argument 'a'\n```\n\n\n可变关键字参数\n\n如下`a`是可变关键字参数：\n```python\ndef f(**a):\n  print(a)\n```\n调用方法：\n```python\nf(a=1) #打印结果为字典：{'a': 1}\nf(a=1,b=2,width=3) #打印结果：{'a': 1, 'b': 2, 'width': 3}\n```\n\n但是，不能这么调用：\n```python\nf(1) TypeError: f() takes 0 positional arguments but 1 was given\n```\n\n\n<center>[上一个例子](157.md)    [下一个例子](159.md)</center>"
  },
  {
    "path": "md/159.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/26\n```\n\n### 列表删除之坑\n\n删除一个列表中的元素，此元素可能在列表中重复多次：\n\n```python\ndef del_item(lst,e):\n    return [lst.remove(i) for i in lst if i==e] # NO!\n```\n\n考虑删除这个序列[1,3,3,3,5]中的元素3，结果发现只删除其中两个：\n\n```python\ndel_item([1,3,3,3,5],3) # 结果：[1,3,5]\n```\n\n正确做法：\n\n```python\ndef del_item(lst,e):\n    d = dict(zip(range(len(lst)),lst)) # YES! 构造字典\n    return [v for k,v in d.items() if v!=e]\n\n```  \n\n<center>[上一个例子](158.md)    [下一个例子](160.md)</center>\n"
  },
  {
    "path": "md/16.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/15\n```\n\n#### 16 执行字符串表示的代码\n\n将字符串编译成python能识别或可执行的代码，也可以将文字读成字符串再编译。\n\n```python\nIn [1]: s  = \"print('helloworld')\"\n    \nIn [2]: r = compile(s,\"<string>\", \"exec\")\n    \nIn [3]: r\nOut[3]: <code object <module> at 0x0000000005DE75D0, file \"<string>\", line 1>\n    \nIn [4]: exec(r)\nhelloworld\n\ns  = \"\"\"\ndef f():\n    a = 100 % 52\n    print(a)\nf()\n\"\"\"\nr = compile(s,\"<string>\", \"exec\")\nexec(r)\n```\n\n输出\n48\n\n<center>[上一个例子](15.md)    [下一个例子](17.md)</center>\n"
  },
  {
    "path": "md/160.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/27\n```\n### 列表快速复制之坑\n\n在python中`*`与列表操作，实现快速元素复制：\n\n```python\na = [1,3,5] * 3 # [1,3,5,1,3,5,1,3,5]\na[0] = 10 # [10, 2, 3, 1, 2, 3, 1, 2, 3]\n```\n\n如果列表元素为列表或字典等复合类型：\n\n```python\na = [[1,3,5],[2,4]] * 3 # [[1, 3, 5], [2, 4], [1, 3, 5], [2, 4], [1, 3, 5], [2, 4]]\n\na[0][0] = 10 #  \n```\n\n结果可能出乎你的意料，其他`a[1[0]`等也被修改为10\n\n```python\n[[10, 3, 5], [2, 4], [10, 3, 5], [2, 4], [10, 3, 5], [2, 4]]\n```\n\n这是因为*复制的复合对象都是浅引用，也就是说id(a[0])与id(a[2])门牌号是相等的。如果想要实现深复制效果，这么做：\n\n```python\na = [[] for _ in range(3)]\n```  \n\n<center>[上一个例子](159.md)    [下一个例子](161.md)</center>"
  },
  {
    "path": "md/161.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/28\n```\n\n### 字符串驻留\n\n```python\nIn [1]: a = 'something'\n    ...: b = 'some'+'thing'\n    ...: id(a)==id(b)\nOut[1]: True\n```\n如果上面例子返回`True`，但是下面例子为什么是`False`:\n```python\nIn [1]: a = '@zglg.com'\n\nIn [2]: b = '@zglg'+'.com'\n\nIn [3]: id(a)==id(b)\nOut[3]: False\n```\n这与Cpython 编译优化相关，行为称为`字符串驻留`，但驻留的字符串中只包含字母，数字或下划线。   \n\n<center>[上一个例子](160.md)    [下一个例子](162.md)</center>"
  },
  {
    "path": "md/162.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/02/29\n```\n\n### 相同值的不可变对象\n```python\nIn [5]: d = {}\n    ...: d[1] = 'java'\n    ...: d[1.0] = 'python'\n\nIn [6]: d\nOut[6]: {1: 'python'}\n\n### key=1,value=java的键值对神奇消失了\nIn [7]: d[1]\nOut[7]: 'python'\nIn [8]: d[1.0]\nOut[8]: 'python'\n```\n这是因为具有相同值的不可变对象在Python中始终具有`相同的哈希值`\n\n由于存在`哈希冲突`，不同值的对象也可能具有相同的哈希值。  \n\n<center>[上一个例子](161.md)    [下一个例子](163.md)</center>"
  },
  {
    "path": "md/163.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/03/01\n```\n\n### 对象销毁顺序\n创建一个类`SE`:\n```python\nclass SE(object):\n  def __init__(self):\n    print('init')\n  def __del__(self):\n    print('del')\n```\n创建两个SE实例，使用`is`判断：\n```python\nIn [63]: SE() is SE()\ninit\ninit\ndel\ndel\nOut[63]: False\n\n```\n创建两个SE实例，使用`id`判断：\n```python\nIn [64]: id(SE()) == id(SE())\ninit\ndel\ninit\ndel\nOut[64]: True\n```\n\n调用`id`函数, Python 创建一个 SE 类的实例，并使用`id`函数获得内存地址后，销毁内存丢弃这个对象。\n\n当连续两次进行此操作, Python会将相同的内存地址分配给第二个对象，所以两个对象的id值是相同的.\n\n\n但是is行为却与之不同，通过打印顺序就可以看到。 \n\n<center>[上一个例子](162.md)    [下一个例子](164.md)</center>"
  },
  {
    "path": "md/164.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/03/02\n```\n\n### 充分认识for\n\n```python\nIn [65]: for i in range(5):\n    ...:   print(i)\n    ...:   i = 10\n0\n1\n2\n3\n4\n```\n为什么不是执行一次就退出？\n\n按照for在Python中的工作方式, i = 10 并不会影响循环。range(5)生成的下一个元素就被解包，并赋值给目标列表的变量`i`.   \n\n<center>[上一个例子](163.md)    [下一个例子](165.md)</center>"
  },
  {
    "path": "md/165.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/03/03\n```\n\n### 认识执行时机\n\n```python\narray = [1, 3, 5]\ng = (x for x in array if array.count(x) > 0)\n```\n`g`为生成器，list(g)后返回`[1,3,5]`，因为每个元素肯定至少都出现一次。所以这个结果这不足为奇。但是，请看下例：\n```python\narray = [1, 3, 5]\ng = (x for x in array if array.count(x) > 0)\narray = [5, 7, 9]\n```\n请问,list(g)等于多少？这不是和上面那个例子结果一样吗，结果也是`[1,3,5]`，但是：\n```python\nIn [74]: list(g)\nOut[74]: [5]\n```\n\n这有些不可思议~~ 原因在于：\n\n生成器表达式中, in 子句在声明时执行, 而条件子句则是在运行时执行。\n\n\n所以代码：\n```python\narray = [1, 3, 5]\ng = (x for x in array if array.count(x) > 0)\narray = [5, 7, 9]\n```\n\n等价于：\n```python\ng = (x for x in [1,3,5] if [5,7,9].count(x) > 0)\n``` \n\n<center>[上一个例子](164.md)    [下一个例子](166.md)</center>"
  },
  {
    "path": "md/166.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/03/04\n```\n\n### 创建空集合错误\n\n这是Python的一个集合：`{1,3,5}`，它里面没有重复元素，在去重等场景有重要应用。下面这样创建空集合是错误的：\n\n```python\nempty = {} #NO!\n```\n\ncpython会解释它为字典\n\n使用内置函数`set()`创建空集合：\n\n```python\nempty = set() #YES!\n``` \n\n<center>[上一个例子](165.md)    [下一个例子](167.md)</center>"
  },
  {
    "path": "md/167.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/03/05\n```\n\n### pyecharts传入Numpy数据绘图失败\n\necharts使用广泛，echarts+python结合后的包：pyecharts，同样可很好用，但是传入Numpy的数据，像下面这样绘图会失败：\n\n```python\nfrom pyecharts.charts import Bar\nimport pyecharts.options as opts\nimport numpy as np\nc = (\n    Bar()\n    .add_xaxis([1, 2, 3, 4, 5])\n    # 传入Numpy数据绘图失败！\n    .add_yaxis(\"商家A\", np.array([0.1, 0.2, 0.3, 0.4, 0.5]))\n)\n\nc.render()\n```\n\n<img src=\"./img/image-20200129164119080.png\" width=\"50%\"/>\n\n由此可见pyecharts对Numpy数据绘图不支持，传入原生Python的list:\n\n```python\nfrom pyecharts.charts import Bar\nimport pyecharts.options as opts\nimport numpy as np\nc = (\n    Bar()\n    .add_xaxis([1, 2, 3, 4, 5])\n    # 传入Python原生list\n    .add_yaxis(\"商家A\", np.array([0.1, 0.2, 0.3, 0.4, 0.5]).tolist())\n)\n\nc.render()\n```\n\n<img src=\"./img/image-20200129164339971.png\" width=\"50%\"/>    \n\n<center>[上一个例子](166.md)    [下一个例子](168.md)</center>"
  },
  {
    "path": "md/168.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/03/06\n```\n\n### 优化代码异常输出包\n\n一行代码优化输出的异常信息\n```python\npip install pretty-errors\n```\n\n写一个函数测试：\n\n```python\ndef divided_zero():\n    for i in range(10, -1, -1):\n        print(10/i)\n\n\ndivided_zero()\n```\n\n在没有import这个`pretty-errors`前，输出的错误信息有些冗余：\n\n```python\nTraceback (most recent call last):\n  File \"c:\\Users\\HUAWEI\\.vscode\\extensions\\ms-python.python-2019.11.50794\\pythonFiles\\ptvsd_launcher.py\", line 43, in <module>\n    main(ptvsdArgs)\n  File \"c:\\Users\\HUAWEI\\.vscode\\extensions\\ms-python.python-2019.11.50794\\pythonFiles\\lib\\python\\old_ptvsd\\ptvsd\\__main__.py\",\nline 432, in main\n    run()\n  File \"c:\\Users\\HUAWEI\\.vscode\\extensions\\ms-python.python-2019.11.50794\\pythonFiles\\lib\\python\\old_ptvsd\\ptvsd\\__main__.py\",\nline 316, in run_file\n    runpy.run_path(target, run_name='__main__')\n  File \"D:\\anaconda3\\lib\\runpy.py\", line 263, in run_path\n    pkg_name=pkg_name, script_name=fname)\n  File \"D:\\anaconda3\\lib\\runpy.py\", line 96, in _run_module_code\n    mod_name, mod_spec, pkg_name, script_name)\n  File \"D:\\anaconda3\\lib\\runpy.py\", line 85, in _run_code\n    exec(code, run_globals)\n  File \"d:\\source\\sorting-visualizer-master\\sorting\\debug_test.py\", line 6, in <module>\n    divided_zero()\n  File \"d:\\source\\sorting-visualizer-master\\sorting\\debug_test.py\", line 3, in divided_zero\n    print(10/i)\nZeroDivisionError: division by zero\n```\n\n我们使用刚安装的`pretty_errors`，`import`下:\n\n```python\nimport pretty_errors\n\ndef divided_zero():\n    for i in range(10, -1, -1):\n        print(10/i)\n\ndivided_zero()\n```\n\n此时看看输出的错误信息，非常精简只有2行，去那些冗余信息：\n\n```python\nZeroDivisionError:\ndivision by zero\n```\n\n完整的输出信息如下图片所示：\n\n<img src=\"./img/errors.png\" width=\"50%\"/>    \n\n<center>[上一个例子](167.md)    [下一个例子](169.md)</center>"
  },
  {
    "path": "md/169.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/03/07\n```\n\n#### 图像处理包pillow\n\n两行代码实现旋转和缩放图像\n\n首先安装pillow:\n\n```python\npip install pillow\n```\n\n旋转图像下面图像45度：\n\n<img src=\"./img/plotly2.png\" width=\"40%\"/>\n\n```python\nIn [1]: from PIL import Image\nIn [2]: im = Image.open('./img/plotly2.png')\nIn [4]: im.rotate(45).show()\n```\n\n旋转45度后的效果图\n\n<img src=\"./img/image-20200105085120611.png\" width=\"40%\"/>\n\n等比例缩放图像：\n\n```python\nim.thumbnail((128,72),Image.ANTIALIAS)\n```\n\n缩放后的效果图：\n\n![](./img/pillow_suofang.png)\n\n\n\n过滤图像后的效果图：\n\n```python\nfrom PIL import ImageFilter\nim.filter(ImageFilter.CONTOUR).show()\n```\n\n<img src=\"./img/pillow_filter.png\" width=\"40%\"/>\n  \n\n<center>[上一个例子](168.md)    [下一个例子](170.md)</center>"
  },
  {
    "path": "md/17.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/15\n```\n\n#### 17 计算表达式\n\n将字符串str 当成有效的表达式来求值并返回计算结果取出字符串中内容\n\n```python\nIn [1]: s = \"1 + 3 +5\"\n\nIn [2]: eval(s)\nOut[2]: 9\n\ns = [\"{'小汽车':10, '面包车':8}\", \"{'面包车':5}\"]\nfrom collections import defaultdict\nd = defaultdict(int)\n\nfor item in s:\n    my_dict = eval(item)\n    print(type(my_dict))\n    for key in my_dict:\n        d[key] += my_dict[key]\nprint(d)\n\n<class 'dict'>\n<class 'dict'>\ndefaultdict(<class 'int'>, {'小汽车': 10, '面包车': 13})\n```\n\n<center>[上一个例子](16.md)    [下一个例子](18.md)</center>\n"
  },
  {
    "path": "md/170.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/03/08\n```\n\n### 一行代码找到编码\n\n兴高采烈地，从网页上抓取一段 `content`\n\n但是，一 `print ` 就不那么兴高采烈了，结果看到一串这个：\n\n```markdown\nb'\\xc8\\xcb\\xc9\\xfa\\xbf\\xe0\\xb6\\xcc\\xa3\\xac\\xce\\xd2\\xd3\\xc3Python'\n```\n\n这是啥？ 又 x 又 c 的！\n\n再一看，哦，原来是十六进制字节串 (`bytes`)，`\\x` 表示十六进制\n\n接下来，你一定想转化为人类能看懂的语言，想到 `decode`：\n\n```python\nIn [3]: b'\\xc8\\xcb\\xc9\\xfa\\xbf\\xe0\\xb6\\xcc\\xa3\\xac\\xce\\xd2\\xd3\\xc3Python'.decode()\nUnicodeDecodeError                        Traceback (most recent call last)\n<ipython-input-3-7d0ea6148880> in <module>\nUnicodeDecodeError: 'utf-8' codec can't decode byte 0xc8 in position 0: invalid continuation byte\n```\n\n马上，一盆冷水泼头上，抛异常了。。。。。\n\n根据提示，`UnicodeDecodeError`，这是 unicode 解码错误。\n\n原来，`decode` 默认的编码方法：`utf-8` \n\n所以排除  b'\\xc8\\xcb\\xc9\\xfa\\xbf\\xe0\\xb6\\xcc\\xa3\\xac\\xce\\xd2\\xd3\\xc3Python' 使用 `utf-8` 的编码方式\n\n可是，这不是四选一选择题啊，逐个排除不正确的！\n\n编码方式几十种，不可能逐个排除吧。\n\n那就猜吧！！！！！！！！！！！！！\n\n**人生苦短，我用Python**\n\n**Python， 怎忍心让你受累呢~**\n\n尽量三行代码解决问题\n\n**第一步，安装 chardet**  它是 char detect 的缩写。\n\n**第二步，pip install chardet**\n\n**第三步，出结果**\n\n```python\nIn [6]: chardet.detect(b'\\xc8\\xcb\\xc9\\xfa\\xbf\\xe0\\xb6\\xcc\\xa3\\xac\\xce\\xd2\\xd3\\xc3Python')\nOut[6]: {'encoding': 'GB2312', 'confidence': 0.99, 'language': 'Chinese'}\n```\n\n编码方法：gb2312\n\n解密字节串：\n\n```python\nIn [7]: b'\\xc8\\xcb\\xc9\\xfa\\xbf\\xe0\\xb6\\xcc\\xa3\\xac\\xce\\xd2\\xd3\\xc3Python'.decode('gb2312')\nOut[7]: '人生苦短，我用Python'\n```\n\n目前，`chardet` 包支持的检测编码几十种。     \n\n<center>[上一个例子](169.md)    [下一个例子](171.md)</center>"
  },
  {
    "path": "md/171.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/03/09\n```\n\n问：子类继承父类的方法吗？\n \n答：子类的实例继承了父类的static_method静态方法，调用该方法，还是调用的父类的方法和类属性。\n\n```python\n# coding:utf-8\n\n\nclass Foo(object):\n    X = 1\n    Y = 2\n\n    @staticmethod\n    def averag(*mixes):\n        return sum(mixes) / len(mixes)\n\n    @staticmethod\n    def static_method():\n        return Foo.averag(Foo.X, Foo.Y)\n\n    @classmethod\n    def class_method(cls):\n        return cls.averag(cls.X, cls.Y)\n\n\nclass Son(Foo):\n    X = 3\n    Y = 5\n\n    @staticmethod\n    def averag(*mixes):\n        return sum(mixes) / 3\n\np = Son()\nprint(p.static_method())\nprint(p.class_method())\n# 1.5\n# 2.6666666666666665\n```\n\n<center>[上一个例子](170.md)    [下一个例子](172.md)</center>"
  },
  {
    "path": "md/172.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc NumPy 的 pad 填充方法\n@tag NumPy \n@version v1.0\n@date 2020/11/27\n```\n\n今天介绍 NumPy 一个实用的方法 `pad`，实现数组周围向外扩展层的功能。\n\n```python\nIn [1]: import numpy as np                                                      \nIn [2]: help(np.pad)                                                            \nIn [4]: a = np.ones((3,4))  \nOut[4]: \narray([[1., 1., 1., 1.],\n       [1., 1., 1., 1.],\n       [1., 1., 1., 1.]])\n```\n\nnp.pad 默认在原数组周边向外扩展 pad_width 层：\n\n```python\nIn [6]: np.pad(a,pad_width=2)                                                   \nOut[6]: \narray([[0., 0., 0., 0., 0., 0., 0., 0.],\n       [0., 0., 0., 0., 0., 0., 0., 0.],\n       [0., 0., 1., 1., 1., 1., 0., 0.],\n       [0., 0., 1., 1., 1., 1., 0., 0.],\n       [0., 0., 1., 1., 1., 1., 0., 0.],\n       [0., 0., 0., 0., 0., 0., 0., 0.],\n       [0., 0., 0., 0., 0., 0., 0., 0.]])\n```\n\n此函数在为数组充填值，卷积中有重要应用。\n\n以上就是《python-small-examples》第 172 个小例子：NumPy 的 pad 填充方法。\n\n<center>[上一个例子](171.md)    [下一个例子](173.md)</center>"
  },
  {
    "path": "md/173.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc 创建一个下对角线为1、2、3、4的对角矩阵\n@tag\n@version \n@date 2020/03/11\n```\n\n```python\nIn [1]: import numpy as np\n\nIn [2]: Z = np.diag(1+np.arange(4),k=-1)\n   ...: print(Z)\n\n[[0 0 0 0 0]\n [1 0 0 0 0]\n [0 2 0 0 0]\n [0 0 3 0 0]\n [0 0 0 4 0]]\n ```\n \n 其中，k 参数：大于0，表示与主对角线上移k，小于0下移k\n\n<center>[上一个例子](172.md)    [下一个例子](174.md)</center>"
  },
  {
    "path": "md/174.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc cut 数据分箱\n@tag\n@version \n@date 2020/11/28\n```\n\n第174个小例子：cut 数据分箱\n\n将百分制分数转为A,B,C,D四个等级，bins 被分为 [0,60,75,90,100]，labels 等于['D', 'C', 'B', 'A']：\n\n```python\n# 生成20个[0,100]的随机整数\nIn [30]: a = np.random.randint(1,100,20)                   \nIn [31]: a                                    \nOut[31]: \narray([48, 22, 46, 84, 13, 52, 36, 35, 27, 99, 31, 37, 15, 31,  5, 46, 98,99, 60, 43])\n\n# cut分箱\nIn [33]: pd.cut(a, [0,60,75,90,100], labels = ['D', 'C', 'B', 'A'])             \nOut[33]: \n[D, D, D, B, D, ..., D, A, A, D, D]\nLength: 20\nCategories (4, object): [D < C < B < A]\n```\n\n分箱后，48分对应D，22分对应D，46对应D，84分对应B，...\n\n<center>[上一个例子](173.md)    [下一个例子](175.md)</center>"
  },
  {
    "path": "md/175.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc 丢弃空值和填充空值\n@tag\n@version \n@date 2020/03/13\n```\n\n丢弃空值\n\nnp.nan 是 pandas 中常见空值，使用 dropna 过滤空值，axis 0 表示按照行，1 表示按列，how 默认为 any ，意思是只要有一个 nan 就过滤某行或某列，all 所有都为 nan\n\n```python\n# axis 0 表示按照行，all 此行所有值都为 nan\ndf.dropna(axis=0, how='all')\n```\n\n充填空值\n\n空值一般使用某个统计值填充，如平均数、众数、中位数等，使用函数 fillna:\n\n```python\n# 使用a列平均数填充列的空值，inplace true表示就地填充\ndf[\"a\"].fillna(df[\"a\"].mean(), inplace=True)\n```\n\n\n\n<center>[上一个例子](174.md)    [下一个例子](176.md)</center>"
  },
  {
    "path": "md/176.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc 一行代码让 pip 安装加速 100 倍\n@tag\n@version \n@date 2020/03/14\n```\n\npip 安装普通方法：\n\n```python\npip install scrapy \n```\n\n这个安装可能是龟速，甚至直接抛出 timeout 异常，然后可能你会加长 socket 延时，通过设置 `defualt-timeout` 参数：\n\n```python\npip --defualt-timeout = 600 install scrapy\n```\n\n但是这不会加快安装速度，直接添加一个参数：\n\n```python\n-i https://pypi.tuna.tsinghua.edu.cn/simple \n```\n\n完整安装命令：\n\n```python\npip --defualt-timeout = 600 install scrapy -i https://pypi.tuna.tsinghua.edu.cn/simple \n```\n\n后面安装你可以直接复制我这行命令，安装包的速度会快很多。\n\n<center>[上一个例子](175.md)    [下一个例子](177.md)</center>"
  },
  {
    "path": "md/177.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc 数据分析神器：deepnote\n@tag\n@version \n@date 2020/03/15\n```\n\n一个和 jupyter notebook很像的神器：deepnote\n\njupyter notebook 是运行 python 非常好用的笔记本之一，尤其作数据分析、数据科学领域应用广泛。最近发现一款兼容 jupyter notebook，极好用的notebook: deepnote\n\n使用也是免费！https://deepnote.com/\n\n它的特点：时事协作，运行在云端\n\n上手使用一下，使用shift+enter 执行代码\n\n------\n\n  执行代码，体验很好，很香：\n\n邀请伙伴直接进入你的notebook，多人协作，开发更快：\n\n多了一种选择，调换着使用它们会很不错！\n\n<center>[上一个例子](176.md)    [下一个例子](178.md)</center>"
  },
  {
    "path": "md/178.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc apply 方法去掉特殊字符\n@tag\n@version \n@date 2020/03/16\n```\n\n### apply 方法去掉特殊字符\n\n某列单元格含有特殊字符，如标点符号，使用元素级操作方法 apply 干掉它们：\n\n```python\nimport string\nexclude = set(string.punctuation)\n\ndef remove_punctuation(x):\n    x = ''.join(ch for ch in x if ch not in exclude)\n    return x\n# 原df\nOut[26]: \n      a       b\n0   c,d  edc.rc\n1     3       3\n2  d ef       4\n\n# 过滤a列标点\nIn [27]: df.a = df.a.apply(remove_punctuation) \nIn [28]: df                \nOut[28]: \n      a       b\n0    cd  edc.rc\n1     3       3\n2  d ef       4\n```\n\n<center>[上一个例子](177.md)    [下一个例子](179.md)</center>"
  },
  {
    "path": "md/179.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc 使用map对列做特征工程\n@tag\n@version \n@date 2020/03/17\n```\n\n**使用map对列做特征工程**\n\n先生成数据：\n\n```python\nd = {\n\"gender\":[\"male\", \"female\", \"male\",\"female\"],\n\"color\":[\"red\", \"green\", \"blue\",\"green\"],\n\"age\":[25, 30, 15, 32]\n}\n\ndf = pd.DataFrame(d)\ndf\n```\n\n\n\n在 `gender` 列上，使用 map 方法，快速完成如下映射：\n\n```python\nd = {\"male\": 0, \"female\": 1}\ndf[\"gender2\"] = df[\"gender\"].map(d)\n```\n\n\n\n<center>[上一个例子](178.md)    [下一个例子](180.md)</center>"
  },
  {
    "path": "md/18.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/16\n```\n\n#### 18 字符串格式化　\n\n格式化输出字符串，format(value, format_spec)实质上是调用了value的__format__(format_spec)方法。\n\n```\nIn [104]: print(\"i am {0},age{1}\".format(\"tom\",18))\ni am tom,age18\n```\n\n| 3.1415926  | {:.2f}  | 3.14      | 保留小数点后两位             |\n| ---------- | ------- | --------- | ---------------------------- |\n| 3.1415926  | {:+.2f} | +3.14     | 带符号保留小数点后两位       |\n| -1         | {:+.2f} | -1.00     | 带符号保留小数点后两位       |\n| 2.71828    | {:.0f}  | 3         | 不带小数                     |\n| 5          | {:0>2d} | 05        | 数字补零 (填充左边, 宽度为2) |\n| 5          | {:x<4d} | 5xxx      | 数字补x (填充右边, 宽度为4)  |\n| 10         | {:x<4d} | 10xx      | 数字补x (填充右边, 宽度为4)  |\n| 1000000    | {:,}    | 1,000,000 | 以逗号分隔的数字格式         |\n| 0.25       | {:.2%}  | 25.00%    | 百分比格式                   |\n| 1000000000 | {:.2e}  | 1.00e+09  | 指数记法                     |\n| 18         | {:>10d} | ' 18'     | 右对齐 (默认, 宽度为10)      |\n| 18         | {:<10d} | '18 '     | 左对齐 (宽度为10)            |\n| 18         | {:^10d} | ' 18 '    | 中间对齐 (宽度为10)          |\n\n<center>[上一个例子](17.md)    [下一个例子](19.md)</center>"
  },
  {
    "path": "md/180.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc category列转数值\n@tag\n@version \n@date 2020/03/18\n```\n\n第 180 个小例子：**category列转数值**\n\n某列取值只可能为有限个枚举值，往往需要转为数值，使用get_dummies，或自己定义函数：\n\n```python\npd.get_dummies(df['a'])\n```\n\n自定义函数，结合 apply:\n\n```python\ndef c2n(x):\n    if x=='A':\n        return 95\n    if x=='B':\n        return 80\n\ndf['a'].apply(c2n)\n```\n\n<center>[上一个例子](179.md)    [下一个例子](181.md)</center>"
  },
  {
    "path": "md/181.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc rank排名\n@tag\n@version \n@date 2020/03/19\n```\n\n第 181 个小例子：**rank排名**\n\nrank 方法，生成数值排名，ascending 为False，考试分数越高，排名越靠前：\n\n```python\nIn [36]: df = pd.DataFrame({'a':[46, 98,99, 60, 43]} )) \nIn [53]: df['a'].rank(ascending=False)                   \nOut[53]: \n0    4.0\n1    2.0\n2    1.0\n3    3.0\n4    5.0\n```\n\n<center>[上一个例子](180.md)    [下一个例子](182.md)</center>"
  },
  {
    "path": "md/182.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc 完成数据下采样，调整步长由小时为天\n@tag\n@version \n@date 2020/03/20\n第 182 个小例子：**完成数据下采样，调整步长由小时为天**\n```\n\n步长为小时的时间序列数据，有没有小技巧，快速完成下采样，采集成按天的数据呢？先生成测试数据：\n\n```python\nimport pandas as pd\nimport numpy as np\ndf = pd.DataFrame(np.random.randint(1,10,size=(240,3)), \\\ncolumns = ['商品编码','商品销量','商品库存'])\n```\n\n```python\ndf.index = pd.util.testing.makeDateIndex(240,freq='H')\ndf\n使用 resample 方法，合并为天(D)\n```\n\n小技巧，使用 resample 方法，合并为天(D)\n```python\nday_df = df.resample(\"D\")[\"商品销量\"].sum().to_frame()\nday_df\n```\n\n果如下，10行，240小时，正好为 10 days:\n\n\n<center>[上一个例子](181.md)    [下一个例子](183.md)</center>"
  },
  {
    "path": "md/183.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc 如何用 Pandas 快速生成时间序列数据？\n@tag\n@version \n@date 2020/03/21\n```\n\n### 第183个小例子：如何用 Pandas 快速生成时间序列数据？\n\n与时间序列相关的问题，平时还是挺常见的。\n\n介绍一个小技巧，使用 `pd.util.testing.makeTimeDataFrame`\n\n只需要一行代码，便能生成一个 index 为时间序列的 DataFrame:\n\n```python\nimport pandas as pd\n\npd.util.testing.makeTimeDataFrame(10)\n```\n\n结果：\n\n```markdown\nA B C D\n2000-01-03 0.932776 -1.509302 0.285825 0.941729\n2000-01-04 0.565230 -1.598449 -0.786274 -0.221476\n2000-01-05 -0.152743 -0.392053 -0.127415 0.841907\n2000-01-06 1.321998 -0.927537 0.205666 -0.041110\n2000-01-07 0.324359 1.512743 0.553633 0.392068\n2000-01-10 -0.566780 0.201565 -0.801172 -1.165768\n2000-01-11 -0.259348 -0.035893 -1.363496 0.475600\n2000-01-12 -0.341700 -1.438874 -0.260598 -0.283653\n2000-01-13 -1.085183 0.286239 2.475605 -1.068053\n2000-01-14 -0.057128 -0.602625 0.461550 0.033472\n```\n\n时间序列的间隔还能配置，默认的 A B C D 四列也支持配置。\n\n```python\nimport numpy as np\n\ndf = pd.DataFrame(np.random.randint(1,1000,size=(10,3)),\n                  columns = ['商品编码','商品销量','商品库存'])\ndf.index = pd.util.testing.makeDateIndex(10,freq='H')\n```\n\n结果：\n\n```markdown\n 商品编码 商品销量 商品库存\n2000-01-01 00:00:00 99 264 98\n2000-01-01 01:00:00 294 406 827\n2000-01-01 02:00:00 89 221 931\n2000-01-01 03:00:00 962 153 956\n2000-01-01 04:00:00 538 46 374\n2000-01-01 05:00:00 226 973 750\n2000-01-01 06:00:00 193 866 7\n2000-01-01 07:00:00 300 129 474\n2000-01-01 08:00:00 966 372 835\n2000-01-01 09:00:00 687 493 910\n```\n\n<center>[上一个例子](182.md)    [下一个例子](184.md)</center>"
  },
  {
    "path": "md/184.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc 如何快速找出 DataFrame 所有列 null 值个数\n@tag\n@version \n@date 2020/12/10\n```\n\n### 第184个小例子：如何快速找出 DataFrame 所有列 null 值个数？\n\n实际使用的数据，null 值在所难免。如何快速找出 DataFrame 所有列的 null 值个数？\n\n使用 Pandas 能非常方便实现，只需下面一行代码：\n\n```python\ndata.isnull().sum()\n```\n\ndata.isnull(): 逐行逐元素查找元素值是否为 null.\n\n.sum(): 默认在 axis 为 0 上完成一次 reduce 求和。\n\n上手实际数据，使用这个小技巧，很爽。\n\n读取泰坦尼克预测生死的数据集\n\n```python\ndata = pd.read_csv('titanicdataset-traincsv/train.csv')\n```\n\n检查 null 值:\n\n```python\ndata.isnull().sum()\n```\n\n结果：\n\n```python\nPassengerId      0\nSurvived         0\nPclass           0\nName             0\nSex              0\nAge            177\nSibSp            0\nParch            0\nTicket           0\nFare             0\nCabin          687\nEmbarked         2\ndtype: int64\n```\n\nAge 列 177 个 null 值\n\nCabin 列 687 个 null 值\n\nEmbarked 列 2 个 null 值\n\n<center>[上一个例子](183.md)    [下一个例子](185.md)</center>"
  },
  {
    "path": "md/185.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/03/23\n```\n\n### 第185个小例子：重新排序 DataFrame 的列\n\n下面给出 2 种简便的小技巧。先构造数据：\n\n```python\ndf = pd.DataFrame(np.random.randint(0,20,size=(5,7)) \\\n,columns=list('ABCDEFG'))\ndf\n```\n\n方法1，直接了当：\n\n```python\ndf2 = df[[\"A\", \"C\", \"D\", \"F\", \"E\", \"G\", \"B\"]]\ndf2\n```\n\n方法2，也了解下：\n\n```python\ncols = df.columns[[0, 2 , 3, 5, 4, 6, 1]]\ndf3 = df[cols]\ndf3\n```\n\n也能得到方法1的结果。\n\n<center>[上一个例子](184.md)    [下一个例子](186.md)</center>"
  },
  {
    "path": "md/186.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/03/24\n```\n\n### 第186个小例子：使用 count 统计词条 出现次数\n\n读入 IMDB-Movie-Data 数据集，1000行数据：\n\n```python\ndf = pd.read_csv(\"../input/imdb-data/IMDB-Movie-Data.csv\")\ndf['Title']\n```\n\n打印 `Title` 列：\n\n```python\n0      Guardians of the Galaxy\n1                   Prometheus\n2                        Split\n3                         Sing\n4                Suicide Squad\n                ...\n995       Secret in Their Eyes\n996            Hostel: Part II\n997     Step Up 2: The Streets\n998               Search Party\n999                 Nine Lives\nName: Title, Length: 1000, dtype: object\n```\n\n标题是由几个单词组成，用空格分隔。\n\n```python\ndf[\"words_count\"] = df[\"Title\"].str.count(\" \") + 1\ndf[[\"Title\",\"words_count\"]]\n```\n\n\n\n<center>[上一个例子](185.md)    [下一个例子](187.md)</center>"
  },
  {
    "path": "md/187.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/03/25\n```\n\n### 第187个小例子：split 求时分(HH:mm)的分钟差\n\nsplit 是更加高效的实现，同样需要先转化为 str 类型：\n\n```python\ndf['a'] = df['a'].astype(str)\ndf['b'] = df['b'].astype(str)\n```\n\n其次 split：\n\n```python\ndf['asplit'] = df['a'].str.split(':')\ndf['bsplit'] = df['b'].str.split(':')\n```\n\n使用 apply 操作每个元素，转化为分钟数：\n\n```python\ndf['amins'] = df['asplit'].apply(lambda x: int(x[0])*60 + int(x[1]))\ndf['bmins'] = df['bsplit'].apply(lambda x: int(x[0])*60 + int(x[1]))\n```\n\n<center>[上一个例子](186.md)    [下一个例子](188.md)</center>"
  },
  {
    "path": "md/188.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/03/26\n```\n\n### 第188个小例子：melt透视数据小技巧\n\nmelt 方法固定某列为一个维度，组合其他列名为另一个维度，实现宽表融化为长表：\n\n```python\n   zip_code  factory  warehouse  retail\n0     12345      100        200       1\n1     56789      400        300       2\n2    101112      500        400       3\n3    131415      600        500       4\n```\n\n固定列`zip_code`，组合`factory`，`warehouse`，`retail` 三个列名为一个维度，按照这种方法凑齐两个维度后，数据一定变长。\n\npandas 的 melt 方法演示如下：\n\n```python\nIn [49]: df = df.melt(id_vars = \"zip_code\") \n```\n\n若melt方法，参数`value_vars`不赋值，默认剩余所有列都是value_vars，所以结果如下：\n\n```python\n    zip_code   variable  value\n0      12345    factory    100\n1      56789    factory    400\n2     101112    factory    500\n3     131415    factory    600\n4      12345  warehouse    200\n5      56789  warehouse    300\n6     101112  warehouse    400\n7     131415  warehouse    500\n8      12345     retail      1\n9      56789     retail      2\n10    101112     retail      3\n11    131415     retail      4\n```\n\n若只想查看 factory 和 retail，则 `value_vars` 赋值为它们即可：\n\n```python\nIn [62]: df_melt2 = df.melt(id_vars = \"zip_code\",value_vars=['factory','reta\n    ...: il'])  \n```\n\n结果：\n\n```python\nzip_code variable  value\n0     12345  factory    100\n1     56789  factory    400\n2    101112  factory    500\n3    131415  factory    600\n4     12345   retail      1\n5     56789   retail      2\n6    101112   retail      3\n7    131415   retail      4\n```\n\nmelt 透视数据后，因为组合多个列为1列，所以数据一定变长。\n\n<center>[上一个例子](187.md)    [下一个例子](189.md)</center>"
  },
  {
    "path": "md/189.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/03/27\n```\n\n### 第189个小例子： pivot 透视小技巧\n\nmelt 是融化数据，而 `pivot` 结冰数据，它们是一对互逆操作。\n\n这是上面 melt 后的数据：\n\n```python\nzip_code variable  value\n0     12345  factory    100\n1     56789  factory    400\n2    101112  factory    500\n3    131415  factory    600\n4     12345   retail      1\n5     56789   retail      2\n6    101112   retail      3\n7    131415   retail      4\n```\n\n现在想要还原为：\n\n```python\nvariable factory retail\nzip_code               \n12345        100      1\n56789        400      2\n101112       500      3\n131415       600      4\n```\n\n如何实现？\n\n使用 `pivot` 方法很容易做到：\n\n```python\ndf_melt2.pivot(index='zip_code',columns='variable')\n```\n\nindex 设定第一个轴，为 zip_code，columns 设定哪些列或哪个列的不同取值组合为一个轴，此处设定为 variable 列，它一共有 2 种不同的取值，分别为 factory, retail，pivot 透视后变为列名，也就是 axis = 1 的轴\n\npivot 方法没有聚合功能，它的升级版为 `pivot_table` 方法，能对数据聚合。\n\n<center>[上一个例子](188.md)    [下一个例子](190.md)</center>"
  },
  {
    "path": "md/19.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/20\n```\n\n#### 19 拿来就用的排序函数\n\n排序：\n\n```python\nIn [1]: a = [1,4,2,3,1]\n\nIn [2]: sorted(a,reverse=True)\nOut[2]: [4, 3, 2, 1, 1]\n\nIn [3]: a = [{'name':'xiaoming','age':18,'gender':'male'},{'name':'\n     ...: xiaohong','age':20,'gender':'female'}]\nIn [4]: sorted(a,key=lambda x: x['age'],reverse=False)\nOut[4]:\n[{'name': 'xiaoming', 'age': 18, 'gender': 'male'},\n {'name': 'xiaohong', 'age': 20, 'gender': 'female'}]\n```\n\n<center>[上一个例子](18.md)    [下一个例子](20.md)</center>"
  },
  {
    "path": "md/190.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc 随机读取文件的K行，生成N个\n@tag\n@version \n@date 2020/03/28\n```\n\n### 第190个小例子： 随机读取文件的K行，生成N个\n\n```python\ndef random_lines_save(filename,gen_file_cnt=10):\n    \"\"\"\n    随机选取文件的某些行并保存，想要生成这类文件的个数由参数\n    @param: gen_file_cnt 指定 \n    \n    @param: filename 读入文件的完整路径\n    @param: gen_file_cnt 想要产生的文件个数\n    \"\"\"\n    df = pd.read_excel(filename)\n    for i in range(gen_file_cnt):\n        n = random.randint(1,len(df))\n        dfs = df.sample(n)\n        dfs.to_excel(str(n)+\".xlsx\",index=False)\n        print(str(n)+\".xlsx\")\n```\n\n这是一个很实用的函数，用于随机生成K行N个文件，使用场景：原来的文件行数较多，想从中随机提取组合N个文件时。\n\n<center>[上一个例子](189.md)    [下一个例子](191.md)</center>"
  },
  {
    "path": "md/191.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc 格式化Pandas的时间列\n@tag\n@version \n@date 2020/03/29\n```\n\n### 第191个小例子： 格式化Pandas的时间列\n\n\n\n```python\nimport pandas as pd \nfrom datetime import datetime, time \n\ndef series_dt_fmt(s:pd.Series,fmt:str)-> pd.Series: \n        \"\"\"\n        根据fmt格式，格式化s列\n        s列是datetime 或者 datetime的str类型，如'2020-12-30 11:44:00' \n        \"\"\"\n        st = pd.to_datetime(s)\n        return st.apply(lambda t: datetime.strftime(t,fmt))\n```\n\n别看只有两行代码，却能实现更加丰富的功能，相比pandas，支持直接返回时分等格式：\n\n```python\ns = pd.Series(['2020-12-30 11:44:00','2020-12-30 11:20:10'])\n\n# 只保留时分\nfmt = '%H:%M'\nseries_dt_fmt(s,fmt)\n\n# 输出结果\n0    11:44\n1    11:20\ndtype: object\n```\n\n<center>[上一个例子](190.md)    [下一个例子](192.md)</center>"
  },
  {
    "path": "md/192.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/03/30\n```\n\n### 192: 创建SQLite连接\n\n编写一个Python程序，创建一个SQLite数据库，并与数据库连接，打印SQLite数据库的版本\n\n一种解决方法：\n\n```python\nimport sqlite3\ntry:\n   sqlite_Connection = sqlite3.connect('temp.db')\n   conn = sqlite_Connection.cursor()\n   print(\"连接到 SQLite.\")\n   sqlite_select_Query = \"select sqlite_version();\"\n   conn.execute(sqlite_select_Query)\n   record = conn.fetchall()\n   print(\"SQLite 数据库的版本是 \", record)\n   conn.close()\nexcept sqlite3.Error as error:\n   print(\"连接到SQLite出错：\", error)\nfinally:\n   if (sqlite_Connection):\n       sqlite_Connection.close()\n       print(\"关闭SQLite连接\")\n```\n\n以上就是第192例，希望对你有用，欢迎点赞支持。\n\n<center>[上一个例子](191.md)    [下一个例子](193.md)</center>"
  },
  {
    "path": "md/193.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/03/31\n```\n\n### 193 json对象转python对象\npython的`json`模块`loads`方法将json对象转为字典，如下所示：\n\n```python\nIn [1]: import json                                                             \n\nIn [2]: json_obj =  '{ \"Name\":\"David\", \"Class\":\"I\", \"Age\":6 }'                  \n\nIn [3]: python_obj = json.loads(json_obj)                                       \n\nIn [4]: type(python_obj)                                                        \nOut[4]: dict\n```\n\n打印查看相关属性\n```python\nprint(\"\\nJSON data:\")\nprint(python_obj)\nprint(\"\\nName: \",python_obj[\"Name\"])\nprint(\"Class: \",python_obj[\"Class\"])\nprint(\"Age: \",python_obj[\"Age\"]) \n```\n\n<center>[上一个例子](192.md)    [下一个例子](194.md)</center>"
  },
  {
    "path": "md/194.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/01\n```\n#### 194 python对象转json对象\n\n```python\nimport json\n# a Python object (dict):\npython_obj = {\n  \"name\": \"David\",\n  \"class\":\"I\",\n  \"age\": 6  \n}\nprint(type(python_obj))\n```\n\n使用`json.dumps`方法转化为json对象：\n```\n# convert into JSON:\nj_data = json.dumps(python_obj)\n\n# result is a JSON string:\nprint(j_data)\n```\n\n##### 带格式转为json\n\n若字典转化为json对象后，保证键有序，且缩进4格，如何做到？\n\n```python\njson.dumps(j_str, sort_keys=True, indent=4)\n```\n\n例子：\n\n```python\nimport json\nj_str = {'4': 5, '6': 7, '1': 3, '2': 4}\nprint(json.dumps(j_str, sort_keys=True, indent=4))\n```\n\n\n\n<center>[上一个例子](193.md)    [下一个例子](195.md)</center>\n\n"
  },
  {
    "path": "md/195.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/02\n```\n#### 195 发现列表前3个最大或最小数\n\n使用堆模块 heapq 里的 nlargest 方法：\n\n```python\nimport heapq as hq\nnums_list = [25, 35, 22, 85, 14, 65, 75, 22, 58]\n\n# Find three largest values\nlargest_nums = hq.nlargest(3, nums_list)\nprint(largest_nums)\n```\n\n相应的求最小3个数，使用堆模块 heapq 里的 nsmallest 方法：\n\n```python\nimport heapq as hq\nnums_list = [25, 35, 22, 85, 14, 65, 75, 22, 58]\nsmallest_nums = hq.nsmallest(3, nums_list)\nprint(\"\\nThree smallest numbers are:\", smallest_nums)\n```\n\n\n\n\n<center>[上一个例子](194.md)    [下一个例子](196.md)</center>"
  },
  {
    "path": "md/196.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/03\n```\n\n### 196 使用堆排序列表为升序\n\n使用 heapq 模块，首先对列表建堆，默认建立小根堆，调用len(nums) 次heapop：\n\n```python\nimport heapq as hq\n\nnums_list = [18, 14, 10, 9, 8, 7, 9, 3, 2, 4, 1]\nhq.heapify(nums_list)\ns_result = [hq.heappop(nums_list) for _ in range(len(nums_list))]\nprint(s_result)\n```\n\n\n<center>[上一个例子](195.md)    [下一个例子](197.md)</center>"
  },
  {
    "path": "md/197.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/04\n```\n\n下面正则适用于提取正整数和大于0的浮点数，参看我的，若有疏漏欢迎补充。\n\n```python\n>>> import re\n>>> pat_integ = '[1-9]+\\d*'\n>>> pat_float0 = '0\\.\\d+[1-9]'\n>>> pat_float1 = '[1-9]\\d*\\.d+'\n>>> pat = 'r%s|%s|%s'%(pat_float_0,pat_float_1,pat_integ)\n>>> re.findall(pat, r)\n['0.78', '3446.73', '0.91', '13642.95', '1.06', '2672.12', '3000']\n```\n\n排除这些串：\n\n000\n000100\n0.00\n000.00\n\n\n解释：`*`表示前一个字符出现0次或多次，`+`表示前一个字符出现1次或多次，`\\d`表示数字[0-9]，`[1-9]`表示1,2,3,4,5,6,7,8,9，`\\.`表示小数点\n\n主要考虑：正整数最左侧一位大于0，大于1的浮点数必须以[1-9]开始，大于0小于1的浮点数小数点前只有1个0.\n\n\n\n\nDay163：使用Python正则 提取出输入一段文字中的所有浮点数和整数 #Python拆书1# \n\n例如： 截至收盘，上证指数涨0.78%，报3446.73点，深证成指涨0.91%，报13642.95点，创业板指涨1.06%，报2672.12点。指数午后震荡走高，碳中和概念强者恒强，板块内上演涨停潮，环保、物业、特高压板块午后涨幅扩大，数字货币板块尾盘冲高，钢铁、煤炭、有色板块全天较为低迷，题材股午后整体回暖，两市上涨个股逾3000家，赚钱效益较好。\n\n提取出所有浮点数和整数： 0.78, 3446.73, 0.91,13642.95 等\n\n\n\t\t     \n\n<center>[上一个例子](196.md)    [下一个例子](198.md)</center>\n"
  },
  {
    "path": "md/198.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/05\n```\n## 1 常见算术运算\n\n```python\nx, y = 3, 2\nprint(x + y) # = 5 \nprint(x - y) # = 1 \nprint(x * y) # = 6 \nprint(x / y) # = 1.5 \nprint(x // y) # = 1 \nprint(x % y) # = 1 \nprint(-x) # = -3 \nprint(abs(-x)) # = 3 \nprint(int(3.9)) # = 3 \nprint(float(x)) # = 3.0 \nprint(x ** y) # = 9\n```\n\n大多数操作符都是不言自明的。注意，`//`运算符执行整数除法。结果是一个向下舍入的整数值（例如，3//2==1）\t\t     \n\n<center>[上一个例子](197.md)    [下一个例子](199.md)</center>\n"
  },
  {
    "path": "md/199.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc 求两点球面距离\n@tag\n@version \n@date 2020/04/06\n```\n\n```python\nEARTH_RADIUS = 6378.137\n\nimport math\n# 角度弧度计算公式\ndef get_radian(degree):\n    return degree * 3.1415926 / 180.0\n# 根据经纬度计算两点之间的距离，得到的单位是 千米\ndef get_distance(lat1,lng1,lat2,lng2):\n    radLat1 = get_radian(lat1)\n    radLat2 = get_radian(lat2)\n    a = radLat1 - radLat2 # 两点纬度差\n    b = get_radian(lng1) - get_radian(lng2); # 两点的经度差\n    s = 2 * math.asin(math.sqrt(math.pow(math.sin(a / 2), 2) + \n                                math.cos(radLat1) * math.cos(radLat2) * math.pow(math.sin(b / 2), 2)));\n    s = s * EARTH_RADIUS\n    return s\n```\t\t     \n\n<center>[上一个例子](198.md)    [下一个例子](200.md)</center>"
  },
  {
    "path": "md/2.md",
    "content": "```markdown\r\n@author jackzhenguo\r\n@desc 进制转化\r\n@date 2019/2/10\r\n```\r\n\r\n#### 2  进制转化\r\n\r\n十进制转换为二进制：\r\n```python\r\nIn [1]: bin(10)                                                                 \r\nOut[1]: '0b1010'\r\n```\r\n\r\n十进制转换为八进制：\r\n```python\r\nIn [2]: oct(9)                                                                  \r\nOut[2]: '0o11'\r\n```\r\n\r\n十进制转换为十六进制：\r\n```python\r\nIn [3]: hex(15)                                                                 \r\nOut[3]: '0xf'\r\n```\r\n\r\n\r\n<center>[上一个例子](1.md)    [下一个例子](3.md)</center>"
  },
  {
    "path": "md/20.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/20\n```\n\n#### 20 求和函数\n\n求和：\n\n```python\nIn [181]: a = [1,4,2,3,1]\n\nIn [182]: sum(a)\nOut[182]: 11\n\nIn [185]: sum(a,10) #求和的初始值为10\nOut[185]: 21\n```\n\n<center>[上一个例子](19.md)    [下一个例子](21.md)</center>"
  },
  {
    "path": "md/200.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc 获取文件编码\n@tag\n@version \n@date 2020/04/07\n```\n\n```python\nimport chardet\nfrom chardet import UniversalDetector\n\ndef get_encoding(file):\n    with open(file, \"rb\") as f:\n        cs = chardet.detect(f.read())\n        return cs['encoding']\n    \n    detector = UniversalDetector()\n    with open(file, \"rb\") as f:\n        for line in f.readlines():\n            detector.feed(line)\n            if detector.done:\n                break\n        detector.close()\n    return detector.result\n```\n\n<center>[上一个例子](199.md)    [下一个例子](201.md)</center>"
  },
  {
    "path": "md/201.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc 格式化json串\n@tag\n@version \n@date 2020/04/08\n```\n```python\nimport json\n\n\ndef format_json(json_str: str):\n    dic = json.loads(json_str)\n\n    js = json.dumps(dic,\n                    sort_keys=True,\n                    ensure_ascii=False,\n                    indent=4,\n                    separators=(', ', ': '))\n    return js\n```\n\t\t     \n\n<center>[上一个例子](200.md)    [下一个例子](202.md)</center>"
  },
  {
    "path": "md/202.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/09\n```\n\t\t     \n\n<center>[上一个例子](201.md)    [下一个例子](203.md)</center>"
  },
  {
    "path": "md/203.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/10\n```\n\t\t     \n\n<center>[上一个例子](202.md)    [下一个例子](204.md)</center>"
  },
  {
    "path": "md/204.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/11\n```\n\t\t     \n\n<center>[上一个例子](203.md)    [下一个例子](205.md)</center>"
  },
  {
    "path": "md/205.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/12\n```\n\t\t     \n\n<center>[上一个例子](204.md)    [下一个例子](206.md)</center>"
  },
  {
    "path": "md/206.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/13\n```\n\t\t     \n\n<center>[上一个例子](205.md)    [下一个例子](207.md)</center>"
  },
  {
    "path": "md/207.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/14\n```\n\t\t     \n\n<center>[上一个例子](206.md)    [下一个例子](208.md)</center>"
  },
  {
    "path": "md/208.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/15\n```\n\t\t     \n\n<center>[上一个例子](207.md)    [下一个例子](209.md)</center>"
  },
  {
    "path": "md/209.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/16\n```\n\t\t     \n\n<center>[上一个例子](208.md)    [下一个例子](210.md)</center>"
  },
  {
    "path": "md/21.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/20\n```\n\n#### 21 nonlocal用于内嵌函数中\n\n关键词`nonlocal`常用于函数嵌套中，声明变量`i`为非局部变量；\n如果不声明，`i+=1`表明`i`为函数`wrapper`内的局部变量，因为在`i+=1`引用(reference)时,i未被声明，所以会报`unreferenced variable`的错误。\n\n```python\ndef excepter(f):\n    i = 0\n    t1 = time.time()\n    def wrapper(): \n        try:\n            f()\n        except Exception as e:\n            nonlocal i\n            i += 1\n            print(f'{e.args[0]}: {i}')\n            t2 = time.time()\n            if i == n:\n                print(f'spending time:{round(t2-t1,2)}')\n    return wrapper\n```\n\n<center>[上一个例子](20.md)    [下一个例子](22.md)</center>"
  },
  {
    "path": "md/210.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/17\n```\n\t\t     \n\n<center>[上一个例子](209.md)    [下一个例子](211.md)</center>"
  },
  {
    "path": "md/211.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/18\n```\n\t\t     \n\n<center>[上一个例子](210.md)    [下一个例子](212.md)</center>"
  },
  {
    "path": "md/212.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/19\n```\n\t\t     \n\n<center>[上一个例子](211.md)    [下一个例子](213.md)</center>"
  },
  {
    "path": "md/213.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/20\n```\n\t\t     \n\n<center>[上一个例子](212.md)    [下一个例子](214.md)</center>"
  },
  {
    "path": "md/214.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/21\n```\n\t\t     \n\n<center>[上一个例子](213.md)    [下一个例子](215.md)</center>"
  },
  {
    "path": "md/215.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/22\n```\n\t\t     \n\n<center>[上一个例子](214.md)    [下一个例子](216.md)</center>"
  },
  {
    "path": "md/216.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/23\n```\n\t\t     \n\n<center>[上一个例子](215.md)    [下一个例子](217.md)</center>"
  },
  {
    "path": "md/217.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/24\n```\n\t\t     \n\n<center>[上一个例子](216.md)    [下一个例子](218.md)</center>"
  },
  {
    "path": "md/218.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/25\n```\n\t\t     \n\n<center>[上一个例子](217.md)    [下一个例子](219.md)</center>"
  },
  {
    "path": "md/219.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/26\n```\n\t\t     \n\n<center>[上一个例子](218.md)    [下一个例子](220.md)</center>"
  },
  {
    "path": "md/22.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/23\n```\n\n#### 22 global 声明全局变量\n\n先回答为什么要有`global`，一个变量被多个函数引用，想让全局变量被所有函数共享。有的伙伴可能会想这还不简单，这样写：\n\n```python\ni = 5\ndef f():\n    print(i)\n\ndef g():\n    print(i)\n    pass\n\nf()\ng()\n\n```\n\nf和g两个函数都能共享变量`i`，程序没有报错，所以他们依然不明白为什么要用`global`.\n\n但是，如果我想要有个函数对`i`递增，这样：\n\n```python\ndef h():\n    i += 1\n\nh()\n```\n\n此时执行程序，bang, 出错了！ 抛出异常：`UnboundLocalError`，原来编译器在解释`i+=1`时会把`i`解析为函数`h()`内的局部变量，很显然在此函数内，编译器找不到对变量`i`的定义，所以会报错。\n\n`global`就是为解决此问题而被提出，在函数h内，显式地告诉编译器`i`为全局变量，然后编译器会在函数外面寻找`i`的定义，执行完`i+=1`后，`i`还为全局变量，值加1：\n\n```python\ni = 0\ndef h():\n    global i\n    i += 1\n\nh()\nprint(i)\n```\n\n<center>[上一个例子](21.md)    [下一个例子](23.md)</center>"
  },
  {
    "path": "md/220.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/27\n```\n\t\t     \n\n<center>[上一个例子](219.md)    [下一个例子](221.md)</center>"
  },
  {
    "path": "md/221.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/28\n```\n\t\t     \n\n<center>[上一个例子](220.md)    [下一个例子](222.md)</center>"
  },
  {
    "path": "md/222.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/29\n```\n\t\t     \n\n<center>[上一个例子](221.md)    [下一个例子](223.md)</center>"
  },
  {
    "path": "md/223.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/04/30\n```\n\t\t     \n\n<center>[上一个例子](222.md)    [下一个例子](224.md)</center>"
  },
  {
    "path": "md/224.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/05/01\n```\n\t\t     \n\n<center>[上一个例子](223.md)    [下一个例子](225.md)</center>"
  },
  {
    "path": "md/225.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/05/02\n```\n\t\t     \n\n<center>[上一个例子](224.md)    [下一个例子](226.md)</center>"
  },
  {
    "path": "md/226.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/05/03\n```\n\t\t     \n\n<center>[上一个例子](225.md)    [下一个例子](227.md)</center>"
  },
  {
    "path": "md/227.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/05/04\n```\n\t\t     \n\n<center>[上一个例子](226.md)    [下一个例子](228.md)</center>"
  },
  {
    "path": "md/228.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/05/05\n```\n\t\t     \n\n<center>[上一个例子](227.md)    [下一个例子](229.md)</center>"
  },
  {
    "path": "md/229.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/05/06\n```\n\t\t     \n\n<center>[上一个例子](228.md)    [下一个例子](230.md)</center>"
  },
  {
    "path": "md/23.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/23\n```\n\n#### 23 交换两元素\n\n理解交换两个元素，需要首先明白什么是pack，什么是unpack\n\n```python\nIn [1]: a=[3,1]                                                                 \n\n# unpack\nIn [2]: a0,a1 = a                                                               \n\nIn [3]: a0                                                                      \nOut[3]: 3\n\nIn [4]: a1                                                                      \nOut[4]: 1\n\n# pack\nIn [5]: b = a0, a1                                                              \n\nIn [6]: b                                                                       \nOut[6]: (3, 1)\n\n```\n\n所以下面 `b,a = a,b` 交换2个元素的过程，实际是先pack a,b为元组 (a,b)，然后再unpack (a,b) 给 b, a的过程\n\n```python\ndef swap(a, b):\n    return b, a\n\n\nprint(swap(1, 0))  # (0,1)\n```\n\n<center>[上一个例子](22.md)    [下一个例子](24.md)</center>\n"
  },
  {
    "path": "md/230.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/05/07\n```\n\t\t     \n\n<center>[上一个例子](229.md)    [下一个例子](231.md)</center>"
  },
  {
    "path": "md/231.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/05/08\n```\n\t\t     \n\n<center>[上一个例子](230.md)    [下一个例子](232.md)</center>"
  },
  {
    "path": "md/232.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/05/09\n```\n\t\t     \n\n<center>[上一个例子](231.md)    [下一个例子](233.md)</center>"
  },
  {
    "path": "md/233.md",
    "content": "\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date 2020/05/10\n```\n\t\t     \n\n<center>[上一个例子](232.md)    [下一个例子](234.md)</center>"
  },
  {
    "path": "md/24.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/25\n```\n\n#### 24 操作函数对象\n\n```python\nIn [31]: def f():\n    ...:     print('i\\'m f')\n\nIn [32]: def g():\n    ...:     print('i\\'m g')\n\nIn [33]: [f,g][1]()\ni'm g\n```\n\n创建函数对象的list，根据想要调用的index，方便统一调用。\n\n<center>[上一个例子](23.md)    [下一个例子](25.md)</center>"
  },
  {
    "path": "md/25.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/25\n```\n\n#### 25 生成逆序序列\n\n```python\nlist(range(10,-1,-1))\n# [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]\n```\n\n第三个参数为负时，表示从第一个参数开始递减，终止到第二个参数(不包括此边界)\n\n<center>[上一个例子](24.md)    [下一个例子](26.md)</center>"
  },
  {
    "path": "md/26.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/27\n```\n\n#### 26 函数的五类参数使用例子\n\npython五类参数：位置参数，关键字参数，默认参数，可变位置或关键字参数的使用。\n\n```python\ndef f(a,*b,c=10,**d):\n  print(f'a:{a},b:{b},c:{c},d:{d}')\n```\n\n*默认参数`c`不能位于可变关键字参数`d`后.*\n\n调用f:\n\n```python\nIn [10]: f(1,2,5,width=10,height=20)\na:1,b:(2, 5),c:10,d:{'width': 10, 'height': 20}\n```\n\n可变位置参数`b`实参后被解析为元组`(2,5)`;而c取得默认值10; d被解析为字典.\n\n再次调用f:\n\n```python\nIn [11]: f(a=1,c=12)\na:1,b:(),c:12,d:{}\n```\n\na=1传入时a就是关键字参数，b,d都未传值，c被传入12，而非默认值。\n\n注意观察参数`a`, 既可以`f(1)`,也可以`f(a=1)` 其可读性比第一种更好，建议使用f(a=1)。如果要强制使用`f(a=1)`，需要在前面添加一个**星号**:\n\n```python\ndef f(*,a,**b):\n  print(f'a:{a},b:{b}')\n```\n\n此时f(1)调用，将会报错：`TypeError: f() takes 0 positional arguments but 1 was given`\n\n只能`f(a=1)`才能OK.\n\n说明前面的`*`发挥作用，它变为只能传入关键字参数，那么如何查看这个参数的类型呢？借助python的`inspect`模块：\n\n```python\nIn [22]: for name,val in signature(f).parameters.items():\n    ...:     print(name,val.kind)\n    ...:\na KEYWORD_ONLY\nb VAR_KEYWORD\n```\n\n可看到参数`a`的类型为`KEYWORD_ONLY`，也就是仅仅为关键字参数。\n\n但是，如果f定义为：\n\n```python\ndef f(a,*b):\n  print(f'a:{a},b:{b}')\n```\n\n查看参数类型：\n\n```python\nIn [24]: for name,val in signature(f).parameters.items():\n    ...:     print(name,val.kind)\n    ...:\na POSITIONAL_OR_KEYWORD\nb VAR_POSITIONAL\n```\n\n可以看到参数`a`既可以是位置参数也可是关键字参数。\n\n<center>[上一个例子](25.md)    [下一个例子](27.md)</center>"
  },
  {
    "path": "md/27.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/27\n```\n\n#### 27  使用slice对象\n\n生成关于蛋糕的序列cake1：\n\n```python\nIn [1]: cake1 = list(range(5,0,-1))\n\nIn [2]: b = cake1[1:10:2]\n\nIn [3]: b\nOut[3]: [4, 2]\n\nIn [4]: cake1\nOut[4]: [5, 4, 3, 2, 1]\n```\n\n再生成一个序列：\n\n```python\nIn [5]: from random import randint\n   ...: cake2 = [randint(1,100) for _ in range(100)]\n   ...: # 同样以间隔为2切前10个元素，得到切片d\n   ...: d = cake2[1:10:2]\nIn [6]: d\nOut[6]: [75, 33, 63, 93, 15]\n```\n\n你看，我们使用同一种切法，分别切开两个蛋糕cake1,cake2. 后来发现这种切法`极为经典`，又拿它去切更多的容器对象。\n\n那么，为什么不把这种切法封装为一个对象呢？于是就有了slice对象。\n\n定义slice对象极为简单，如把上面的切法定义成slice对象：\n\n```python\nperfect_cake_slice_way = slice(1,10,2)\n#去切cake1\ncake1_slice = cake1[perfect_cake_slice_way] \ncake2_slice = cake2[perfect_cake_slice_way]\n\nIn [11]: cake1_slice\nOut[11]: [4, 2]\n\nIn [12]: cake2_slice\nOut[12]: [75, 33, 63, 93, 15]\n```\n\n与上面的结果一致。\n\n对于逆向序列切片，`slice`对象一样可行：\n\n```python\na = [1,3,5,7,9,0,3,5,7]\na_ = a[5:1:-1]\n\nnamed_slice = slice(5,1,-1)\na_slice = a[named_slice] \n\nIn [14]: a_\nOut[14]: [0, 9, 7, 5]\n\nIn [15]: a_slice\nOut[15]: [0, 9, 7, 5]\n```\n\n频繁使用同一切片的操作可使用slice对象抽出来，复用的同时还能提高代码可读性。\n\n<center>[上一个例子](26.md)    [下一个例子](28.md)</center>"
  },
  {
    "path": "md/28.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/2\n```\n\n#### 28  lambda 函数的动画演示\n\n有些读者反映，`lambda`函数不太会用，问我能不能解释一下。\n\n比如，下面求这个 `lambda`函数：\n\n```python\ndef max_len(*lists):\n    return max(*lists, key=lambda v: len(v))\n```\n\n有两点疑惑：\n\n- 参数`v`的取值？ \n- `lambda`函数有返回值吗？如果有，返回值是多少？\n\n调用上面函数，求出以下三个最长的列表：\n\n```python\nr = max_len([1, 2, 3], [4, 5, 6, 7], [8])\nprint(f'更长的列表是{r}')\n```\n\n\n结论：\n\n- 参数v的可能取值为`*lists`，也就是 `tuple` 的一个元素。\n\n- `lambda`函数返回值，等于`lambda v`冒号后表达式的返回值。\n\n<center>[上一个例子](27.md)    [下一个例子](29.md)</center>"
  },
  {
    "path": "md/29.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/2\n```\n\n#### 29  转为字典　　\n\n创建数据字典\n\n```python\n# 方法1：使用dict\nIn [1]: dict()\nOut[1]: {}\nIn [2]: dict(a='a',b='b')\nOut[2]: {'a': 'a', 'b': 'b'}\n\n# 方法2：zip\nIn [3]: dict(zip(['a','b'],[1,2]))\nOut[3]: {'a': 1, 'b': 2}\n\n# 方法3：嵌入元组的列表\nIn [4]: dict([('a',1),('b',2)])\nOut[4]: {'a': 1, 'b': 2}\n\n# 方法4：自典型字符串\nIn [1]: s = \"{'a':1, 'b':2}\"                                                    \nIn [2]: eval(s)                                                                 \nOut[2]: {'a': 1, 'b': 2}\n```\n\n<center>[上一个例子](28.md)    [下一个例子](30.md)</center>\n"
  },
  {
    "path": "md/3.md",
    "content": "```markdown\r\n@author jackzhenguo\r\n@desc 整数和ASCII互转\r\n@date 2019/2/10\r\n```\r\n\r\n#### 3 整数和ASCII互转\r\n\r\n十进制整数对应的`ASCII字符`\r\n```python\r\nIn [1]: chr(65)\r\nOut[1]: 'A'\r\n```\r\n\r\n查看某个`ASCII字符`对应的十进制数\r\n```python\r\nIn [1]: ord('A')\r\nOut[1]: 65\r\n```\n\n<center>[上一个例子](2.md)    [下一个例子](4.md)</center>"
  },
  {
    "path": "md/30.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/4\n```\n\n#### 30 冻结集合　　\n\n创建一个不可修改的集合。\n\n```python\nIn [1]: frozenset([1,1,3,2,3])\nOut[1]: frozenset({1, 2, 3})\n```\n\n因为不可修改，所以没有像`set`那样的`add`和`pop`方法\n\n<center>[上一个例子](29.md)    [下一个例子](31.md)</center>"
  },
  {
    "path": "md/31.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/4\n```\n\n#### 31 转为集合类型\n\n返回一个set对象，集合内不允许有重复元素：\n\n```python\nIn [1]: a = [1,4,2,3,1]\n\nIn [2]: set(a)\nOut[2]: {1, 2, 3, 4}\n\nIn [3]: b = set(a)\n\nIn [4]: b.add(5)\n\nIn [5]: b\nOut[5]: {1, 2, 3, 4, 5}\n\nIn [6]: b.pop()\nOut[6]: 1\n\nIn [7]: b\nOut[7]: {2, 3, 4, 5}\n\nIn [8]: b.pop()\nOut[8]: 2\n\nIn [9]: b\nOut[9]: {3, 4, 5}\n\n# 注意pop删除集合内任意一个元素\nIn [10]: help(b.pop)\nHelp on built-in function pop:\n\npop(...) method of builtins.set instance\n    Remove and return an arbitrary set element.\n    Raises KeyError if the set is empty.\n```\n\n<center>[上一个例子](30.md)    [下一个例子](32.md)</center>\n"
  },
  {
    "path": "md/32.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/4\n```\n\n#### 32 转元组\n\n `tuple()` 将对象转为一个不可变的序列类型\n\n ```python\n In [16]: i_am_list = [1,3,5]\n In [17]: i_am_tuple = tuple(i_am_list)\n In [18]: i_am_tuple\n Out[18]: (1, 3, 5)\n ```\n\n<center>[上一个例子](31.md)    [下一个例子](33.md)</center>"
  },
  {
    "path": "md/33.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/6\n```\n\n#### 33 对象是否可调用　　\n\n检查对象是否可被调用\n\n```python\nIn [1]: callable(str)\nOut[1]: True\n\nIn [2]: callable(int)\nOut[2]: True\n```\n\n```python\nIn [18]: class Student(): \n    ...:     def __init__(self,id,name): \n    ...:         self.id = id \n    ...:         self.name = name \n    ...:     def __repr__(self): \n    ...:         return 'id = '+self.id +', name = '+self.name \n    ...\n\nIn [19]: xiaoming = Student('001','xiaoming')                                   \n\nIn [20]: callable(xiaoming)                                                     \nOut[20]: False\n```\n如果能调用`xiaoming()`, 需要重写`Student`类的`__call__`方法：\n\n```python\nIn [1]: class Student():\n    ...:     def __init__(self,id,name):\n    ...:         self.id = id\n    ...:         self.name = name\n    ...:     def __repr__(self):\n    ...:         return 'id = '+self.id +', name = '+self.name\n    ...:     def __call__(self):\n    ...:         print('I can be called')\n    ...:         print(f'my name is {self.name}')\n    ...: \n\nIn [2]: t = Student('001','xiaoming')\n\nIn [3]: t()\nI can be called\nmy name is xiaoming\n```\n\n<center>[上一个例子](32.md)    [下一个例子](34.md)</center>"
  },
  {
    "path": "md/34.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/10\n```\n\n#### 34  ascii 展示对象　　\n\n调用对象的 `__repr__` 方法，获得该方法的返回值，如下例子返回值为字符串\n\n```python\n>>> class Student():\n    def __init__(self,id,name):\n        self.id = id\n        self.name = name\n    def __repr__(self):\n        return 'id = '+self.id +', name = '+self.name\n```\n调用：\n```python\n>>> xiaoming = Student(id='1',name='xiaoming')\n>>> xiaoming\nid = 1, name = xiaoming\n>>> ascii(xiaoming)\n'id = 1, name = xiaoming'\n```\n\n<center>[上一个例子](33.md)    [下一个例子](35.md)</center>"
  },
  {
    "path": "md/35.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/10\n```\n\n#### 35 类方法　\n\n`classmethod` 装饰器对应的函数不需要实例化，不需要 `self `参数。\n\n但第一个参数需要是表示自身类的 `cls` 参数，可以来调用类的属性，类的方法，实例化对象等。\n\n```python\nIn [1]: class Student():\n    ...:     def __init__(self,id,name):\n    ...:         self.id = id\n    ...:         self.name = name\n    ...:     def __repr__(self):\n    ...:         return 'id = '+self.id +', name = '+self.name\n    ...:     @classmethod\n    ...:     def f(cls):\n    ...:         print(cls)\n```\n\n<center>[上一个例子](34.md)    [下一个例子](36.md)</center>"
  },
  {
    "path": "md/36.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/10\n```\n\n#### 36 动态删除属性　　\n\n```python\n>>> class Student():\n    def __init__(self,id,name):\n        self.id = id\n        self.name = name\n    def __repr__(self):\n        return 'id = '+self.id +', name = '+self.name\n```\n调用：\n```python\n>>> xiaoming = Student(id='1',name='xiaoming')\n>>> xiaoming\nid = 1, name = xiaoming\n>>> ascii(xiaoming)\n'id = 1, name = xiaoming'\n```\n\n删除对象的属性\n\n```python\nIn [1]: delattr(xiaoming,'id')\n\nIn [2]: hasattr(xiaoming,'id')\nOut[2]: False\n```\n\n<center>[上一个例子](35.md)    [下一个例子](37.md)</center>"
  },
  {
    "path": "md/37.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/10\n```\n\n#### 37 一键查看对象所有方法　\n\n不带参数时返回`当前范围`内的变量、方法和定义的类型列表；带参数时返回`参数`的属性，方法列表。\n\n```python\nIn [96]: dir(xiaoming)\nOut[96]:\n['__class__',\n '__delattr__',\n '__dict__',\n '__dir__',\n '__doc__',\n '__eq__',\n '__format__',\n '__ge__',\n '__getattribute__',\n '__gt__',\n '__hash__',\n '__init__',\n '__init_subclass__',\n '__le__',\n '__lt__',\n '__module__',\n '__ne__',\n '__new__',\n '__reduce__',\n '__reduce_ex__',\n '__repr__',\n '__setattr__',\n '__sizeof__',\n '__str__',\n '__subclasshook__',\n '__weakref__',\n \n 'name']\n```\n\n<center>[上一个例子](36.md)    [下一个例子](38.md)</center>"
  },
  {
    "path": "md/38.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/10\n```\n\n#### 38 动态获取对象属性　\n\n获取对象的属性\n\n```python\nIn [1]: class Student():\n   ...:     def __init__(self,id,name):\n   ...:         self.id = id\n   ...:         self.name = name\n   ...:     def __repr__(self):\n   ...:         return 'id = '+self.id +', name = '+self.name\n\nIn [2]: xiaoming = Student(id='001',name='xiaoming')\nIn [3]: getattr(xiaoming,'name') # 获取xiaoming这个实例的name属性值\nOut[3]: 'xiaoming'\n```\n\n<center>[上一个例子](37.md)    [下一个例子](39.md)</center>"
  },
  {
    "path": "md/39.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/10\n```\n\n#### 39 对象是否有某个属性\n\n```python\nIn [1]: class Student():\n   ...:     def __init__(self,id,name):\n   ...:         self.id = id\n   ...:         self.name = name\n   ...:     def __repr__(self):\n   ...:         return 'id = '+self.id +', name = '+self.name\n\nIn [2]: xiaoming = Student(id='001',name='xiaoming')\nIn [3]: hasattr(xiaoming,'name')\nOut[3]: True\n\nIn [4]: hasattr(xiaoming,'address')\nOut[4]: False\n```\n\n<center>[上一个例子](38.md)    [下一个例子](40.md)</center>"
  },
  {
    "path": "md/4.md",
    "content": "```markdown\r\n@author jackzhenguo\r\n@desc 元素都为真检查\r\n@date 2019/2/10\r\n```\r\n\r\n#### 4 元素都为真检查\r\n\r\n所有元素都为真，返回 `True`，否则为`False`\r\n```python\r\nIn [5]: all([1,0,3,6])                                                          \r\nOut[5]: False\r\n```\r\n```python\r\nIn [6]: all([1,2,3])                                                            \r\nOut[6]: True\r\n```\n\n<center>[上一个例子](3.md)    [下一个例子](5.md)</center>"
  },
  {
    "path": "md/40.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/10\n```\n\n#### 40 对象门牌号　\n\n```python\nIn [1]: class Student():\n   ...:     def __init__(self,id,name):\n   ...:         self.id = id\n   ...:         self.name = name\n   ...:     def __repr__(self):\n   ...:         return 'id = '+self.id +', name = '+self.name\n\nIn [2]: xiaoming = Student(id='001',name='xiaoming')\n```\n\n返回对象的内存地址\n\n```python\nIn [1]: id(xiaoming)\nOut[1]: 98234208\n```\n\n<center>[上一个例子](39.md)    [下一个例子](41.md)</center>"
  },
  {
    "path": "md/41.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/13\n```\n\n#### 41 isinstance\n\n判断*object*是否为类*classinfo*的实例，是返回true\n\n```python\nIn [1]: class Student():\n   ...:     def __init__(self,id,name):\n   ...:         self.id = id\n   ...:         self.name = name\n   ...:     def __repr__(self):\n   ...:         return 'id = '+self.id +', name = '+self.name\n\nIn [2]: xiaoming = Student(id='001',name='xiaoming')\n\nIn [3]: isinstance(xiaoming,Student)\nOut[3]: True\n```\n\n<center>[上一个例子](40.md)    [下一个例子](42.md)</center>"
  },
  {
    "path": "md/42.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/13\n```\n\n#### 42 issubclass父子关系鉴定\n\n```python\nIn [1]: class undergraduate(Student):\n    ...:     def studyClass(self):\n    ...:         pass\n    ...:     def attendActivity(self):\n    ...:         pass\n\nIn [2]: issubclass(undergraduate,Student)\nOut[2]: True\n\nIn [3]: issubclass(object,Student)\nOut[3]: False\n\nIn [4]: issubclass(Student,object)\nOut[4]: True\n```\n\n如果class是classinfo元组中某个元素的子类，也会返回True\n\n```python\nIn [1]: issubclass(int,(int,float))\nOut[1]: True\n```\n\n<center>[上一个例子](41.md)    [下一个例子](43.md)</center>"
  },
  {
    "path": "md/43.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/15\n```\n\n#### 43 所有对象之根\n\nobject 是所有类的基类\n\n```python\nIn [1]: o = object()\n\nIn [2]: type(o)\nOut[2]: object\n```\n\n<center>[上一个例子](42.md)    [下一个例子](44.md)</center>"
  },
  {
    "path": "md/44.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/16\n```\n\n#### 44  创建属性的两种方式\n\n返回 property 属性，典型的用法：\n\n```python\nclass C:\n    def __init__(self):\n        self._x = None\n\n    def getx(self):\n        return self._x\n\n    def setx(self, value):\n        self._x = value\n\n    def delx(self):\n        del self._x\n    # 使用property类创建 property 属性\n    x = property(getx, setx, delx, \"I'm the 'x' property.\")\n```\n\n使用python装饰器，实现与上完全一样的效果代码：\n\n```python\nclass C:\n    def __init__(self):\n        self._x = None\n\n    @property\n    def x(self):\n        return self._x\n\n    @x.setter\n    def x(self, value):\n        self._x = value\n\n    @x.deleter\n    def x(self):\n        del self._x\n```\n\n<center>[上一个例子](43.md)    [下一个例子](45.md)</center>"
  },
  {
    "path": "md/45.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/10\n```\n\n#### 45 查看对象类型\n\n*class* `type`(*name*, *bases*, *dict*)\n\n传入一个参数时，返回 *object* 的类型：\n\n```python\nIn [1]: class Student():\n   ...:     def __init__(self,id,name):\n   ...:         self.id = id\n   ...:         self.name = name\n   ...:     def __repr__(self):\n   ...:         return 'id = '+self.id +', name = '+self.name\n   ...: \n\nIn [2]: xiaoming = Student(id='001',name='xiaoming')\nIn [3]: type(xiaoming)\nOut[3]: __main__.Student\n\nIn [4]: type(tuple())\nOut[4]: tuple\n```\n\n<center>[上一个例子](44.md)    [下一个例子](46.md)</center>"
  },
  {
    "path": "md/46.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/4\n```\n\n#### 46 元类使用介绍\n\n`xiaoming`, `xiaohong`, `xiaozhang` 都是学生，这类群体叫做 `Student`. \n\nPython 定义类的常见方法，使用关键字 `class`\n\n```python\nIn [36]: class Student(object):\n    ...:     pass\n```\n\n`xiaoming`, `xiaohong`, `xiaozhang` 是类的实例，则：\n\n```python\nxiaoming = Student()\nxiaohong = Student()\nxiaozhang = Student()\n```\n\n创建后，xiaoming 的 `__class__` 属性，返回的便是 `Student`类\n\n```python\nIn [38]: xiaoming.__class__\nOut[38]: __main__.Student\n```\n\n问题在于，`Student` 类有 `__class__`属性，如果有，返回的又是什么？\n\n```python\nIn [39]: xiaoming.__class__.__class__\nOut[39]: type\n```\n\n哇，程序没报错，返回 `type`\n\n那么，我们不妨猜测：`Student` 类，类型就是 `type`\n\n换句话说，`Student`类就是一个**对象**，它的类型就是 `type`\n\n所以，Python 中一切皆对象，**类也是对象**\n\nPython 中，将描述 `Student` 类的类被称为：元类。\n\n按照此逻辑延伸，描述元类的类被称为：*元元类*，开玩笑了~ 描述元类的类也被称为元类。\n\n聪明的朋友会问了，既然 `Student` 类可创建实例，那么 `type` 类可创建实例吗？ 如果能，它创建的实例就叫：类 了。 你们真聪明！\n\n说对了，`type` 类一定能创建实例，比如 `Student` 类了。\n\n```python\nIn [40]: Student = type('Student',(),{})\n\nIn [41]: Student\nOut[41]: __main__.Student\n```\n\n它与使用 `class` 关键字创建的 `Student` 类一模一样。\n\nPython 的类，因为又是对象，所以和 `xiaoming`，`xiaohong` 对象操作相似。支持：\n\n- 赋值\n- 拷贝\n- 添加属性\n- 作为函数参数\n\n```python\nIn [43]: StudentMirror = Student # 类直接赋值 # 类直接赋值\nIn [44]: Student.class_property = 'class_property' # 添加类属性\nIn [46]: hasattr(Student, 'class_property')\nOut[46]: True\n```\n\n元类，确实使用不是那么多，也许先了解这些，就能应付一些场合。就连 Python 界的领袖 `Tim Peters` 都说：\n\n“元类就是深度的魔法，99%的用户应该根本不必为此操心。\n\n<center>[上一个例子](45.md)    [下一个例子](47.md)</center>"
  },
  {
    "path": "md/47.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/4\n```\n\n#### 47 枚举对象　　\n\n返回一个可以枚举的对象，该对象的next()方法将返回一个元组。\n\n```python\nIn [1]: s = [\"a\",\"b\",\"c\"]\n    ...: for i ,v in enumerate(s,1):\n    ...:     print(i,v)\n    ...:\n1 a\n2 b\n3 c\n```\n\n<center>[上一个例子](46.md)    [下一个例子](48.md)</center>"
  },
  {
    "path": "md/48.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/4\n```\n\n#### 48 查看变量所占字节数\n`getsizeof`查看变量占用字节数\n看到：字典比列表占用更多空间\n\n```python\nIn [1]: import sys\n\nIn [3]: a = [('a',1),('b',2)]                                                                                                             \n\nIn [5]: sys.getsizeof(a)                                                        \nOut[5]: 88\n\n\nIn [6]: a = {'a':1,'b':2.0}                                                     \nIn [7]: sys.getsizeof(a)                                                        \nOut[7]: 248\n\n```\n\n<center>[上一个例子](47.md)    [下一个例子](49.md)</center>\n"
  },
  {
    "path": "md/49.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/4\n```\n\n#### 49 过滤器　　\n\n在函数中设定过滤条件，迭代元素，保留返回值为`True`的元素：\n\n```python\nIn [1]: fil = filter(lambda x: x>10,[1,11,2,45,7,6,13])\n\nIn [2]: list(fil)\nOut[2]: [11, 45, 13]\n```\n\n<center>[上一个例子](48.md)    [下一个例子](50.md)</center>"
  },
  {
    "path": "md/5.md",
    "content": "```markdown\r\n@author jackzhenguo\r\n@desc 至少一个为真检查\r\n@date 2019/2/10\r\n```\r\n\r\n#### 5 至少一个为真检查　\r\n\r\n至少有一个元素为真返回`True`，否则`False`\r\n```python\r\nIn [7]: any([0,0,0,[]])                                                         \r\nOut[7]: False\r\n```\r\n\r\n```python\r\nIn [8]: any([0,0,1])                                                            \r\nOut[8]: True\r\n```\n\n<center>[上一个例子](4.md)    [下一个例子](6.md)</center>"
  },
  {
    "path": "md/50.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/4\n```\n\n#### 50 返回对象哈希值　　\n\n返回对象的哈希值，值得注意的是自定义的实例都是可哈希的，`list`, `dict`, `set`等可变对象都是不可哈希的(unhashable)\n\n  ```python\nIn [1]: hash(xiaoming)\nOut[1]: 6139638\n\nIn [2]: hash([1,2,3])\n# TypeError: unhashable type: 'list'\n  ```\n\n<center>[上一个例子](49.md)    [下一个例子](51.md)</center>"
  },
  {
    "path": "md/51.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/4\n```\n\n#### 51  help 一键帮助　\n\n返回对象的帮助文档\n\n```python\nIn [1]: help(xiaoming)\nHelp on Student in module __main__ object:\n\nclass Student(builtins.object)\n |  Methods defined here:\n |\n |  __init__(self, id, name)\n |\n |  __repr__(self)\n |\n |  Data descriptors defined here:\n |\n |  __dict__\n |      dictionary for instance variables (if defined)\n |\n |  __weakref__\n |      list of weak references to the object (if defined)\n```\n\n<center>[上一个例子](50.md)    [下一个例子](52.md)</center>"
  },
  {
    "path": "md/52.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/4\n```\n\n### 52 获取用户输入　\n\n获取用户输入内容\n\n```python\nIn [1]: input()\naa\nOut[1]: 'aa'\n```\n\n<center>[上一个例子](51.md)    [下一个例子](53.md)</center>"
  },
  {
    "path": "md/53.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/8\n```\n\n#### 53 创建迭代器\n\n使用`iter(obj, sentinel)`, 返回一个可迭代对象, sentinel可省略(一旦迭代到此元素，立即终止)\n\n```python\nIn [1]: lst = [1,3,5]\n\nIn [2]: for i in iter(lst):\n    ...:     print(i)\n    ...:\n1\n3\n5\n```\n\n```python\nIn [1]: class TestIter(object):\n    ...:     def __init__(self):\n    ...:         self.l=[1,3,2,3,4,5]\n    ...:         self.i=iter(self.l)\n    ...:     def __call__(self):  #定义了__call__方法的类的实例是可调用的\n    ...:         item = next(self.i)\n    ...:         print (\"__call__ is called,fowhich would return\",item)\n    ...:         return item\n    ...:     def __iter__(self): #支持迭代协议(即定义有__iter__()函数)\n    ...:         print (\"__iter__ is called!!\")\n    ...:         return iter(self.l)\nIn [2]: t = TestIter()\nIn [3]: t() # 因为实现了__call__，所以t实例能被调用\n__call__ is called,which would return 1\nOut[3]: 1\n\nIn [4]: for e in TestIter(): # 因为实现了__iter__方法，所以t能被迭代\n    ...:     print(e)\n    ...: \n__iter__ is called!!\n1\n3\n2\n3\n4\n5\n```\n\n<center>[上一个例子](52.md)    [下一个例子](54.md)</center>"
  },
  {
    "path": "md/54.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/20\n```\n\n#### 54 文件读写和mode 取值表\n\n返回文件对象\n\n```python\nIn [1]: fo = open('D:/a.txt',mode='r', encoding='utf-8')\n\nIn [2]: fo.read()\nOut[2]: '\\ufefflife is not so long,\\nI use Python to play.'\nIn [3]: fo.close() # 关闭文件对象\n```\n\nmode 取值表：\n\n| 字符  | 意义                             |\n| :---- | :------------------------------- |\n| `'r'` | 读取（默认）                     |\n| `'w'` | 写入，并先截断文件               |\n| `'x'` | 排它性创建，如果文件已存在则失败 |\n| `'a'` | 写入，如果文件存在则在末尾追加   |\n| `'b'` | 二进制模式                       |\n| `'t'` | 文本模式（默认）                 |\n| `'+'` | 打开用于更新（读取与写入）       |\n\n文件读操作\n\n```python\nimport os\n# 创建文件夹\n\ndef mkdir(path):\n    isexists = os.path.exists(path)\n    if not isexists:\n        os.mkdir(path)\n# 读取文件信息\n\ndef openfile(filename):\n    f = open(filename)\n    fllist = f.read()\n    f.close()\n    return fllist  # 返回读取内容\n```\n\n文件写操作\n\n```python\n# 写入文件信息\n# example1\n# w写入，如果文件存在，则清空内容后写入，不存在则创建\nf = open(r\"./data/test.txt\", \"w\", encoding=\"utf-8\")\nprint(f.write(\"测试文件写入\"))\nf.close\n\n# example2\n# a写入，文件存在，则在文件内容后追加写入，不存在则创建\nf = open(r\"./data/test.txt\", \"a\", encoding=\"utf-8\")\nprint(f.write(\"测试文件写入\"))\nf.close\n\n# example3\n# with关键字系统会自动关闭文件和处理异常\nwith open(r\"./data/test.txt\", \"w\") as f:\n    f.write(\"hello world!\")\n```\n\n<center>[上一个例子](53.md)    [下一个例子](55.md)</center>"
  },
  {
    "path": "md/55.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/10\n```\n\n#### 55 创建range序列\n\n1) range(stop)\n2) range(start, stop[,step])\n\n生成一个不可变序列：\n\n```python\nIn [1]: range(11)\nOut[1]: range(0, 11)\n\nIn [2]: range(0,11,1)\nOut[2]: range(0, 11)\n```\n\n<center>[上一个例子](54.md)    [下一个例子](56.md)</center>"
  },
  {
    "path": "md/56.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/20\n```\n\n#### 56 反向迭代器reversed\n\n```python\nIn [1]: rev = reversed([1,4,2,3,1])\n\nIn [2]: for i in rev:\n     ...:     print(i)\n     ...:\n1\n3\n2\n4\n1\n```\n\n<center>[上一个例子](55.md)    [下一个例子](57.md)</center>"
  },
  {
    "path": "md/57.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/20\n```\n\n#### 57 zip迭代器\n\n创建一个聚合了来自每个可迭代对象中的元素的迭代器：\n\n```python\nIn [1]: x = [3,2,1]\nIn [2]: y = [4,5,6]\nIn [3]: list(zip(y,x))\nOut[3]: [(4, 3), (5, 2), (6, 1)]\n\nIn [4]: a = range(5)\nIn [5]: b = list('abcde')\nIn [6]: b\nOut[6]: ['a', 'b', 'c', 'd', 'e']\nIn [7]: [str(y) + str(x) for x,y in zip(a,b)]\nOut[7]: ['a0', 'b1', 'c2', 'd3', 'e4']\n```\n\n<center>[上一个例子](56.md)    [下一个例子](58.md)</center>"
  },
  {
    "path": "md/58.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/23\n```\n\n#### 58 operator使用举例\n\n```python\nfrom operator import (add, sub)\n\n\ndef add_or_sub(a, b, oper):\n    return (add if oper == '+' else sub)(a, b)\n\n\nadd_or_sub(1, 2, '-')  # -1\n```\n\n<center>[上一个例子](57.md)    [下一个例子](59.md)</center>"
  },
  {
    "path": "md/59.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/25\n```\n\n#### 60 传输json对象\n\n对象序列化，是指将内存中的对象转化为可存储或传输的过程。很多场景，直接一个类对象，传输不方便。\n\n但是，当对象序列化后，就会更加方便，因为约定俗成的，接口间的调用或者发起的 web 请求，一般使用 json 串传输。\n\n实际使用中，一般对类对象序列化。先创建一个 Student 类型，并创建两个实例。\n\n```python\nclass Student():\n    def __init__(self,**args):\n        self.ids = args['ids']\n        self.name = args['name']\n        self.address = args['address']\nxiaoming = Student(ids = 1,name = 'xiaoming',address = '北京')\nxiaohong = Student(ids = 2,name = 'xiaohong',address = '南京')\n```\n\n导入 json 模块，调用 dump 方法，就会将列表对象 [xiaoming,xiaohong]，序列化到文件 json.txt 中。\n\n```python\nimport json\n\nwith open('json.txt', 'w') as f:\n    json.dump([xiaoming,xiaohong], f, default=lambda obj: obj.__dict__, ensure_ascii=False, indent=2, sort_keys=True)\n```\n\n生成的文件内容，如下：\n\n```json\n[\n    {\n        \"address\":\"北京\",\n        \"ids\":1,\n        \"name\":\"xiaoming\"\n    },\n    {\n        \"address\":\"南京\",\n        \"ids\":2,\n        \"name\":\"xiaohong\"\n    }\n]\n```\n\n<center>[上一个例子](58.md)    [下一个例子](60.md)</center>"
  },
  {
    "path": "md/6.md",
    "content": "```markdown\n@author jackzhenguo\n@desc 判断是真是假\n@date 2019/2/12\n```\n\n#### 6 判断是真是假　　\n\n测试一个对象是True, 还是False.\n```python\nIn [9]: bool([0,0,0])                                                           \nOut[9]: True\n\nIn [10]: bool([])                                                               \nOut[10]: False\n\nIn [11]: bool([1,0,1])                                                          \nOut[11]: True\n```\n\n\n<center>[上一个例子](5.md)    [下一个例子](7.md)</center>"
  },
  {
    "path": "md/60.md",
    "content": "#### 61 不用else和if实现计算器\n\n```python\nfrom operator import *\n\n\ndef calculator(a, b, k):\n    return {\n        '+': add,\n        '-': sub,\n        '*': mul,\n        '/': truediv,\n        '**': pow\n    }[k](a, b)\n\n\ncalculator(1, 2, '+')  # 3\ncalculator(3, 4, '**')  # 81\n```\n\n<center>[上一个例子](59.md)    [下一个例子](61.md)</center>"
  },
  {
    "path": "md/61.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/3/25\n```\n\n#### 61 去最求平均\n\n```python\ndef score_mean(lst):\n    lst.sort()\n    lst2=lst[1:(len(lst)-1)]\n    return round((sum(lst2)/len(lst2)),1)\n\nlst=[9.1, 9.0,8.1, 9.7, 19,8.2, 8.6,9.8]\nscore_mean(lst) # 9.1\n```\n\n<center>[上一个例子](60.md)    [下一个例子](62.md)</center>"
  },
  {
    "path": "md/62.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/2\n```\n\n#### 62 打印99乘法表\n\n打印出如下格式的乘法表\n\n```python\n1*1=1\n1*2=2   2*2=4\n1*3=3   2*3=6   3*3=9\n1*4=4   2*4=8   3*4=12  4*4=16\n1*5=5   2*5=10  3*5=15  4*5=20  5*5=25\n1*6=6   2*6=12  3*6=18  4*6=24  5*6=30  6*6=36\n1*7=7   2*7=14  3*7=21  4*7=28  5*7=35  6*7=42  7*7=49\n1*8=8   2*8=16  3*8=24  4*8=32  5*8=40  6*8=48  7*8=56  8*8=64\n1*9=9   2*9=18  3*9=27  4*9=36  5*9=45  6*9=54  7*9=63  8*9=72  9*9=81\n```\n\n一共有10 行，第`i`行的第`j`列等于：`j*i`，\n\n其中,\n\n `i`取值范围：`1<=i<=9`\n\n `j`取值范围：`1<=j<=i`\n\n根据`例子分析`的语言描述，转化为如下代码：\n\n```python\nfor i in range(1, 10):\n    for j in range(1, i+1):\n        print('%d * %d = %d' % (j, i, j * i) , end=\"\\t\")\n    print()\n```\n\n<center>[上一个例子](61.md)    [下一个例子](63.md)</center>"
  },
  {
    "path": "md/63.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/2\n```\n\n#### 63 递归版flatten函数\n\n对于如下数组：\n\n```\n[[[1,2,3],[4,5]]]\n```\n\n如何完全展开成一维的。这个小例子实现的`flatten`是递归版，两个参数分别表示带展开的数组，输出数组。\n\n```python\nfrom collections.abc import *\n\ndef flatten(lst, out_lst=None):\n    if out_lst is None:\n        out_lst = []\n    for i in lst:\n        if isinstance(i, Iterable): # 判断i是否可迭代\n            flatten(i, out_lst)  # 尾数递归\n        else:\n            out_lst.append(i)    # 产生结果\n    return out_lst\n```\n\n调用`flatten`:\n\n```python\nprint(flatten([[1,2,3],[4,5]]))\nprint(flatten([[1,2,3],[4,5]], [6,7]))\nprint(flatten([[[1,2,3],[4,5,6]]]))\n# 结果：\n[1, 2, 3, 4, 5]\n[6, 7, 1, 2, 3, 4, 5]\n[1, 2, 3, 4, 5, 6]\n```\n\nnumpy里的`flatten`与上面的函数实现有些微妙的不同：\n\n```python\nimport numpy\nb = numpy.array([[1,2,3],[4,5]])\nb.flatten()\narray([list([1, 2, 3]), list([4, 5])], dtype=object)\n```\n\n<center>[上一个例子](62.md)    [下一个例子](64.md)</center>"
  },
  {
    "path": "md/64.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/2\n```\n\n#### 64 列表等分\n\n```python\nfrom math import ceil\n\ndef divide(lst, size):\n    if size <= 0:\n        return [lst]\n    return [lst[i * size:(i+1)*size] for i in range(0, ceil(len(lst) / size))]\n```\n\n测试举例：\n\n```python\nr = divide([1, 3, 5, 7, 9], 2)\nprint(r)  # [[1, 3], [5, 7], [9]]\n\nr = divide([1, 3, 5, 7, 9], 0)\nprint(r)  # [[1, 3, 5, 7, 9]]\n\nr = divide([1, 3, 5, 7, 9], -3)\nprint(r)  # [[1, 3, 5, 7, 9]]\n```\n\n\n\n<center>[上一个例子](63.md)    [下一个例子](65.md)</center>"
  },
  {
    "path": "md/65.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/6\n```\n\n#### 65 压缩列表\n\n```python\ndef filter_false(lst):\n    return list(filter(bool, lst))\n\n\nr = filter_false([None, 0, False, '', [], 'ok', [1, 2]])\nprint(r)  # ['ok', [1, 2]]\n\n```\n\n<center>[上一个例子](64.md)    [下一个例子](66.md)</center>"
  },
  {
    "path": "md/66.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/6\n```\n\n#### 66 求更长的列表\n\n```python\ndef max_length(*lst):\n    return max(*lst, key=lambda v: len(v))\n\n\nr = max_length([1, 2, 3], [4, 5, 6, 7], [8])\nprint(f'更长的列表是{r}')  # [4, 5, 6, 7]\n\nr = max_length([1, 2, 3], [4, 5, 6, 7], [8, 9])\nprint(f'更长的列表是{r}')  # [4, 5, 6, 7]\n```\n\n<center>[上一个例子](65.md)    [下一个例子](67.md)</center>"
  },
  {
    "path": "md/67.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/6\n```\n\n#### 67 求众数\n\n```python\ndef top1(lst):\n    return max(lst, default='列表为空', key=lambda v: lst.count(v))\n```\n\n测试举例：\n\n```python\nlst = [1, 3, 3, 2, 1, 1, 2]\nr = top1(lst)\nprint(f'{lst}中出现次数最多的元素为:{r}')  \n# [1, 3, 3, 2, 1, 1, 2]中出现次数最多的元素为:1\n```\n\n\n\n<center>[上一个例子](66.md)    [下一个例子](68.md)</center>"
  },
  {
    "path": "md/68.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/10\n```\n\n#### 68 所有多个列表的最大值\n```python \ndef max_lists(*lst):\n    return max(max(*lst, key=lambda v: max(v)))\n\n\nr = max_lists([1, 2, 3], [6, 7, 8], [4, 5])\nprint(r)  # 8\n```\n\n<center>[上一个例子](67.md)    [下一个例子](69.md)</center>"
  },
  {
    "path": "md/69.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/10\n```\n\n#### 69 列表检查重复\n\n```python\ndef has_duplicates(lst):\n    return len(lst) == len(set(lst))\n\n\nx = [1, 1, 2, 2, 3, 2, 3, 4, 5, 6]\ny = [1, 2, 3, 4, 5]\nhas_duplicates(x)  # False\nhas_duplicates(y)  # True\n```\n\n<center>[上一个例子](68.md)    [下一个例子](70.md)</center>"
  },
  {
    "path": "md/7.md",
    "content": "```markdown\n@author jackzhenguo\n@desc 创建复数\n@date 2019/2/13\n```\n\n#### 7  创建复数\n\n创建一个复数\n\n```python\nIn [1]: complex(1,2)\nOut[1]: (1+2j)\n```\n\n\n<center>[上一个例子](6.md)    [下一个例子](8.md)</center>"
  },
  {
    "path": "md/70.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/10\n```\n\n#### 70 一行代码实现列表反转\n\n```python\ndef reverse(lst):\n    return lst[::-1]\n\n\nr = reverse([1, -2, 3, 4, 1, 2])\nprint(r)  # [2, 1, 4, 3, -2, 1]\n```\n\n<center>[上一个例子](69.md)    [下一个例子](71.md)</center>"
  },
  {
    "path": "md/71.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/14\n```\n\n#### 71 浮点数等差数列\n\n```python\ndef float_range(start, stop, n):\n    start,stop,n = float('%.2f' % start), float('%.2f' % stop),int('%.d' % n)\n    step = (stop-start)/n\n    lst = [start]\n    while n > 0:\n        start,n = start+step,n-1\n        lst.append(round((start), 2))\n    return lst\n```\n\n测试举例：\n\n```python\nfloat_range(1, 8, 10) \n# [1.0, 1.7, 2.4, 3.1, 3.8, 4.5, 5.2, 5.9, 6.6, 7.3, 8.0]\n```\n\n\n\n<center>[上一个例子](70.md)    [下一个例子](72.md)</center>"
  },
  {
    "path": "md/72.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/15\n```\n\n#### 72 按条件分组\n\n```python\ndef bif_by(lst, f):\n    return [ [x for x in lst if f(x)],[x for x in lst if not f(x)]]\n```\n\n测试举例：\n\n```python\nrecords = [25,89,31,34] \nbif_by(records, lambda x: x<80) # [[25, 31, 34], [89]]\n```\n\n\n\n<center>[上一个例子](71.md)    [下一个例子](73.md)</center>"
  },
  {
    "path": "md/73.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/15\n```\n\n#### 73 map实现向量运算\n\n多序列运算函数\n\n`map(function,iterabel,iterable2)`\n\n```python\nlst1=[1,2,3,4,5,6]\nlst2=[3,4,5,6,3,2]\nlist(map(lambda x,y:x*y+1,lst1,lst2))\n### [4, 9, 16, 25, 16, 13]\n```\n\n<center>[上一个例子](72.md)    [下一个例子](74.md)</center>"
  },
  {
    "path": "md/74.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/15\n```\n\n#### 74 值最大的字典\n\n```python\ndef max_pairs(dic):\n    if len(dic) == 0:\n        return dic\n    max_val = max(map(lambda v: v[1], dic.items()))\n    return [item for item in dic.items() if item[1] == max_val]\n```\n\n测试举例：\n\n```python\nr = max_pairs({'a': -10, 'b': 5, 'c': 3, 'd': 5})\nprint(r)  # [('b', 5), ('d', 5)]\n```\n\n\n\n<center>[上一个例子](73.md)    [下一个例子](75.md)</center>"
  },
  {
    "path": "md/75.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/15\n```\n\n#### 75 合并两个字典\n\nPython 3.5 后支持的一行代码实现合并字典\n\n```python\ndef merge_dict(dic1, dic2):\n    return {**dic1, **dic2} \n```\n\n测试：\n\n```python\nmerge_dict({'a': 1, 'b': 2}, {'c': 3}) \n# {'a': 1, 'b': 2, 'c': 3}\n```\n\n\n\n<center>[上一个例子](74.md)    [下一个例子](76.md)</center>"
  },
  {
    "path": "md/76.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/19\n```\n\n#### 76 Topn 字典\n\n返回字典d前n个最大值对应的键\n\n```python\nfrom heapq import nlargest\ndef topn_dict(d, n):\n    return nlargest(n, d, key=lambda k: d[k])\n```\n\n测试：\n\n```python\ntopn_dict({'a': 10, 'b': 8, 'c': 9, 'd': 10}, 3)  \n# ['a', 'd', 'c']\n```\n\n\n\n<center>[上一个例子](75.md)    [下一个例子](77.md)</center>"
  },
  {
    "path": "md/77.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/19\n```\n\n#### 77 异位词\n\n两个字符串含有相同字母，但排序不同，简称：互为变位词\n\n```python\nfrom collections import Counter\n\n# \n\ndef anagram(str1, str2):\n    return Counter(str1) == Counter(str2)\n\nanagram('eleven+two', 'twelve+one')  # True 这是一对神器的变位词\nanagram('eleven', 'twelve')  # False\n```\n\n<center>[上一个例子](76.md)    [下一个例子](78.md)</center>"
  },
  {
    "path": "md/78.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/23\n```\n\n#### 78 逻辑上合并字典\n(1) 两种合并字典方法\n这是一般的字典合并写法\n\n```python\ndic1 = {'x': 1, 'y': 2 }\ndic2 = {'y': 3, 'z': 4 }\nmerged1 = {**dic1, **dic2} # {'x': 1, 'y': 3, 'z': 4}\n```\n\n修改merged['x']=10，dic1中的x值`不变`，`merged`是重新生成的一个`新字典`。\n\n但是，`ChainMap`却不同，它在内部创建了一个容纳这些字典的列表。因此使用ChainMap合并字典，修改merged['x']=10后，dic1中的x值`改变`，如下所示：\n\n```python\nfrom collections import ChainMap\nmerged2 = ChainMap(dic1,dic2)\nprint(merged2) # ChainMap({'x': 1, 'y': 2}, {'y': 3, 'z': 4})\n```\n\n<center>[上一个例子](77.md)    [下一个例子](79.md)</center>"
  },
  {
    "path": "md/79.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/4/26\n```\n\n#### 79  带名字的元组\n\n定义名字为Point的元祖，字段属性有`x`,`y`,`z`\n\n```python\nfrom collections import namedtuple\nPoint = namedtuple('Point', ['x', 'y', 'z'])  \nlst = [Point(1.5, 2, 3.0), Point(-0.3, -1.0, 2.1), Point(1.3, 2.8, -2.5)]\nprint(lst[0].y - lst[1].y)\n```\n\n使用命名元组写出来的代码可读性更好，尤其处理上百上千个属性时作用更加凸显。\n\n<center>[上一个例子](78.md)    [下一个例子](80.md)</center>"
  },
  {
    "path": "md/8.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/2/10\n```\n\n#### 8 取商和余数　　\n\n分别取商和余数\n\n```python\nIn [1]: divmod(10,3)\nOut[1]: (3, 1)\n```\n\n\n<center>[上一个例子](7.md)    [下一个例子](9.md)</center>"
  },
  {
    "path": "md/80.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/5/1\n```\n\n#### 80 sample 样本抽样\n\n使用`sample`抽样，如下例子从100个样本中随机抽样10个。\n\n```python\nfrom random import randint,sample\nlst = [randint(0,50) for _ in range(100)]\nprint(lst[:5])# [38, 19, 11, 3, 6]\nlst_sample = sample(lst,10)\nprint(lst_sample) # [33, 40, 35, 49, 24, 15, 48, 29, 37, 24]\n```\n\n<center>[上一个例子](79.md)    [下一个例子](81.md)</center>"
  },
  {
    "path": "md/81.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/5/1\n```\n\n#### 81 shuffle 重洗数据集\n\n使用`shuffle`用来重洗数据集，值得注意`shuffle`是对lst就地(in place)洗牌，节省存储空间。\n\n```python\nfrom random import shuffle\nlst = [randint(0,50) for _ in range(100)]\nshuffle(lst)\nprint(lst[:5]) # [50, 3, 48, 1, 26]\n```\n\n<center>[上一个例子](80.md)    [下一个例子](82.md)</center>"
  },
  {
    "path": "md/82.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/5/1\n```\n\n#### 82 10个均匀分布的坐标点\n\nrandom模块中的`uniform(a,b)`生成[a,b)内的一个随机数。\n\n如下生成10个均匀分布的二维坐标点\n\n```python\nfrom random import uniform\nIn [1]: [(uniform(0,10),uniform(0,10)) for _ in range(10)]\nOut[1]: \n[(9.244361194237328, 7.684326645514235),\n (8.129267671737324, 9.988395854203773),\n (9.505278771040661, 2.8650440524834107),\n (3.84320100484284, 1.7687190176304601),\n (6.095385729409376, 2.377133802224657),\n (8.522913365698605, 3.2395995841267844),\n (8.827829601859406, 3.9298809217233766),\n (1.4749644859469302, 8.038753079253127),\n (9.005430657826324, 7.58011186920019),\n (8.700789540392917, 1.2217577293254112)]\n```\n\n<center>[上一个例子](81.md)    [下一个例子](83.md)</center>"
  },
  {
    "path": "md/83.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/5/3\n```\n\n#### 83 10个高斯分布的坐标点\n\nrandom模块中的`gauss(u,sigma)`生成均值为u, 标准差为sigma的满足高斯分布的值，如下生成10个二维坐标点，样本误差(y-2*x-1)满足均值为0，标准差为1的高斯分布：\n\n```python\nfrom random import gauss\nx = range(10)\ny = [2*xi+1+gauss(0,1) for xi in x]\npoints = list(zip(x,y))\n### 10个二维点：\n[(0, -0.86789025305992),\n (1, 4.738439437453464),\n (2, 5.190278040856102),\n (3, 8.05270893133576),\n (4, 9.979481700775292),\n (5, 11.960781766216384),\n (6, 13.025427054303737),\n (7, 14.02384035204836),\n (8, 15.33755823101161),\n (9, 17.565074449028497)]\n```\n\n<center>[上一个例子](82.md)    [下一个例子](84.md)</center>"
  },
  {
    "path": "md/84.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/5/4\n```\n\n#### 84 chain串联小容器为大容器\n\n`chain`函数串联a和b，兼顾内存效率同时写法更加优雅。\n\n```python\nfrom itertools import chain\na = [1,3,5,0]\nb = (2,4,6)\n\nfor i in chain(a,b):\n  print(i)\n### 结果\n1\n3\n5\n0\n2\n4\n6\n```\n\n<center>[上一个例子](83.md)    [下一个例子](85.md)</center>"
  },
  {
    "path": "md/85.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/5/5\n```\n\n#### 85 product 案例\n\n```python\ndef product(*args, repeat=1):\n    pools = [tuple(pool) for pool in args] * repeat\n    result = [[]]\n    for pool in pools:\n        result = [x+[y] for x in result for y in pool]\n    for prod in result:\n        yield tuple(prod)\n```\n\n\n调用函数：\n\n```python\nrtn = product('xyz', '12', repeat=3)\nprint(list(rtn))\n```\n\n<center>[上一个例子](84.md)    [下一个例子](86.md)</center>"
  },
  {
    "path": "md/86.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/5/6\n```\n\n#### 86 反转字符串的两个方法\n\n```python\nst=\"python\"\n```\n\n方法1：\n\n```python\n''.join(reversed(st))\n```\n\n方法2:\n\n```python\nst[::-1]\n```\n\n\n\n<center>[上一个例子](85.md)    [下一个例子](87.md)</center>"
  },
  {
    "path": "md/87.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/5/7\n```\n\n#### 87 join 串联字符串\n\n用逗号连接字符串\n\n```python\nIn [4]: mystr = ['1','2','java','4','python','java','7','8','java','python','11','java','13','14']\n\nIn [5]: ','.join(mystr) #用逗号连接字符串\nOut[5]: '1,2,java,4,python,java,7,8,java,python,11,java,13,14'\n```\n\n<center>[上一个例子](86.md)    [下一个例子](88.md)</center>"
  },
  {
    "path": "md/88.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/5/3\n```\n\n#### 88 字符串字节长度\n\n```python\ndef str_byte_len(mystr):\n    return (len(mystr.encode('utf-8')))\n```\n\n测试：\n\n```python\nstr_byte_len('i love python')  # 13(个字节)\nstr_byte_len('字符')  # 6(个字节)\n```\n\n\n\n<center>[上一个例子](87.md)    [下一个例子](89.md)</center>"
  },
  {
    "path": "md/89.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/5/10\n```\n\n### 89 正则中字符 `r`是干啥的？\n\n经常见过正则表达式前有一个字符 `r`，它的作用是告诉解释器后面的一串是原生字符串，按照字面意思解释即可。如：\n\n```python\ns1 = r'\\n.*'\nprint(s1) \n```\n\n它告诉编译器s串第一个字符是`\\`，第二个字符是`n`.打印的结果就是它本身：\n\n```python\n\\n.*\n```\n\n而如果不带前缀字符`r`，即：\n\n```python\ns2 = '\\n.*'\nprint(s2)\n```\n\n解释器认为前两个字符`\\n`为转义字符，一个新行的意思，打印结果为一个换行加.*，如下所示：\n\n```python\n.*\n```\n\n<center>[上一个例子](88.md)    [下一个例子](90.md)</center>"
  },
  {
    "path": "md/9.md",
    "content": "```markdown\n@author jackzhenguo\n@desc 转为浮点类型　\n@date 2019/2/15\n```\n#### 9 转为浮点类型　\n\n将一个整数或数值型字符串转换为浮点数\n\n```python\nIn [1]: float(3)\nOut[1]: 3.0\n```\n\n```python\nIn [1]: float('3')\nOut[1]: 3.0\n```\n\n浮点数最大值\n```python\nimport sys\n\nIn[4]: sys.float_info.max                                                      \nOut[4]: 1.7976931348623157e+308\n```\n\n正无穷大、负无穷大\n```python\nfloat('inf') # 正无穷大\nfloat('-inf') # 负无穷大\n```\n\n如果不能转化为浮点数，则会报`ValueError`:\n\n```python\nIn [2]: float('a')\n# ValueError: could not convert string to float: 'a'\n```\n\n<center>[上一个例子](8.md)    [下一个例子](10.md)</center>\n"
  },
  {
    "path": "md/90.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/5/15\n```\n\n### 90 什么是一个原子操作？\n\n微观世界中，如果定义原子是组成事物的最基本单元，那么就可理解为原子不能再分了。同理此处，正则的原子操作是指不能再被分割的正则表达式操作。\n\n如正则中的`+`指前面的一个原子操作出现至少1次。\n\n例如：`66+`表示第一个字符为6，第二个字符6和第三个字符+联合起来表示至少出现1次字符6，因此综合起来至少要有2个6紧邻的串才能满足此正则表达式(下面会详细讲到)。\n\n`\\w+`表示*字母数字下划线*中的任意一个字符(`\\w`指代的)至少出现1次，那么`\\w`就是一个原子操作。\n\n因此，普通字符是原子，正则中的通用字符(下面会讲到)也是原子。\n\n大家记住*原子*这个概念。\n\n<center>[上一个例子](89.md)    [下一个例子](91.md)</center>"
  },
  {
    "path": "md/91.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/6/3\n```\n\n### 91 怎么理解正则中的转义？\n\n正则世界中，重新定义了几个新的转义字符。\n\n一个转义字符`\\`+一个字符，转义后会改变原字符的意义，它不再是它，而是赋予一个新的含义。\n\n例如，`w`本身就是一个英文字符`w`，没有其他任何含义。但是，前面加一个转义字符 `\\` 后，含义发生重大改变，`w`它不再是`w`，而是`\\`要与`w`连在一起，被解释器解释为匹配以下字符集合中的任意一个：\n\n```python\npat = '\\w'\n```\n\n等于：\n\n```python\npat = '[0123456789\n      AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz\n      _]'\n```\n\n即匹配数字、大小写字母和下划线`_`字符集合中的任意一个。\n\n你看，一个通用转义字符`\\w`直接就指代上面这一大串，写法多么简便，同时在正则的世界里又经常被用到，故被称为：**通用正则字符**\n\n类似的通用正则字符还有几个，下面也会讲到。\n\n做一件事前，把规则弄清，触类旁通，相信大家理解其他几个也没问题。\n\n<center>[上一个例子](90.md)    [下一个例子](92.md)</center>"
  },
  {
    "path": "md/92.md",
    "content": "### 92 正则最普通查找\n\n最普通查找就是需要找啥就写啥，没有使用正则的规则。如下是关于小说《灿烂千阳》中的一段话，从中找出单词`friendship`，可能出现多次：\n\n```\ns = \"\"\"\n# Mariam is only fifteen \n# when she is sent to Kabul to marry the troubled and bitter Rasheed,\n# who is thirty years her senior. \n# Nearly two decades later, \n# in a climate of growing unrest, tragedy strikes fifteen-year-old Laila, \n# who must leave her home and join Mariam's unhappy household. \n# Laila and Mariam are to find consolation in each other, \n# their friendship to grow as deep as the bond between sisters, \n# as strong as the ties between mother and daughter. \n# With the passing of time comes Taliban rule over Afghanistan, \n# the streets of Kabul loud with the sound of gunfire and bombs, \n# life a desperate struggle against starvation, brutality and fear, \n# the women's endurance tested beyond their worst imaginings. \n# Yet love can move a person to act in unexpected ways, \n# lead them to overcome the most daunting obstacles with a startling heroism. \n# In the end it is love that triumphs over death and destruction. \n# A Thousand Splendid Suns is an unforgettable portrait of a wounded country and\n#  a deeply moving story of family and friendship. \n#  It is a beautiful, heart-wrenching story of an unforgiving time, \n#  an unlikely bond and an indestructible love.\n\"\"\"\n```\n\n使用正则前，先导入re模块，再定义正则表达式，然后使用`findall`方法找出所有匹配\n\n```python\nimport re\npat = 'friendship'\nresult = re.findall(pat,s)\nprint(result) \n\n# 共找到两处：\n# ['friendship', 'friendship']\n```\n\n以上就是使用正则的最普通例子。如果要找出前缀为grow的单词，比如可能为grows, growing 等，最普通查找实现起来就不方便。\n\n然而，借助于下面介绍的元字符、通用字符和捕获组合起来，便能应对解决复杂的匹配查找问题。\n\n<center>[上一个例子](91.md)    [下一个例子](93.md)</center>"
  },
  {
    "path": "md/93.md",
    "content": "### 93 使用通用字符查找\n\n在正则的世界里，通用字符指帮助我们更加简便的写出匹配规则的字符。\n\n如上面文字，下面正则匹配串能找出以d开始，[a-z]表示的任意一个小写英文字符，{7}表示小写英文字符出现7次(下面情况3会说到)，也就是匹配出来的子串长度为1+7=8:\n\n```python\npat = 'd[a-z]{7}'\nresult = re.findall(pat,s)\n```\n\n匹配结果为：\n\n```python\n['daughter', 'desperat', 'daunting', 'destruct', 'destruct']\n```\n\n同理，模式串`pat = 'd[a-z]{10}'`匹配的结果为：\n\n```\n['destruction', 'destructibl']\n```\n\n模式串`pat = 'd[a-z]{11}'`匹配的结果为：\n\n```\n[ 'destructible']\n```\n\n你看，通用字符`[a-z]`使用真方便，5个字符一下就表达了所有26个小写的字符，但是注意`[a-z]`匹配26个小写字符的任意**一个**.\n\n类似功能的通用字符还包括：\n\n```\n[A-Z]  匹配大写英文字母\n[0-9]  匹配一个0-9之间的数字\n```\n\n还有更加强大的通用字符：\n\n```\n\\s  匹配空白字符，如\\n \\t \\b等\n\\w  匹配任意字母、数字、下划线 \n\\d  匹配十进制数字0-9\n```\n\n而\\S, \\W, \\D 分别对应 \\s, \\w, \\d匹配字符集的补集，例如\\S 的意思是匹配 \\s 以外的其他任意字符。\n\n\n\n<center>[上一个例子](92.md)    [下一个例子](94.md)</center>"
  },
  {
    "path": "md/94.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/7/3\n```\n\n### 94 使用元字符查找\n\n`元`的含义大家不妨理解为用来描述它后面事物的类，如*元类*用来创建描述类的类，*元模型*描述一个模型的模型，因此推而广之，*元字符*用来描述字符的字符。\n\n理解以上后，你再看正则中使用最普遍的一个元字符 `+`，它是用来描述前面一个原子出现次数的字符，表示前一个原子出现1次或多次都可。\n\n例如，在寻找手机靓号时，正则表达式`66+`，表示前一个原子`6`至少出现1次，因此连上第一个6，表示电话号码中至少有两个66紧邻。因此，电话号码`18612652166`、`17566665656`都满足要求，而号码`18616161616`不符合要求。\n\n类似功能的元字符，还包括如下。功能相似，不再赘述：\n\n```\n* 前面的原子重复0次、1次、多次 \n? 前面的原子重复0次或者1次 \n+ 前面的原子重复1次或多次\n{n} 前面的原子出现了 n 次\n{n,} 前面的原子至少出现 n 次\n{n,m} 前面的原子出现次数介于 n-m 之间\n```\n\n<center>[上一个例子](93.md)    [下一个例子](95.md)</center>"
  },
  {
    "path": "md/95.md",
    "content": "## 95 捕获子串\n\n今天以我写过的《Python 60天》专栏中的一段文字，提取出里面的链接为例，阐述提取子串的实用性。\n\n先贴上文字(有删减改动)，将这段文字赋值给变量 `urls`：\n\n```\nurls = \"\"\"\n基于 Python 的包更是枝繁叶茂，遍地开花，“Tiobe 编程语言排行榜”最新统计显示 Python 是增长最快的语言。\n\n![image-20200131192231967](https://images.gitbook.cn/2020-02-05-014719.png)\n\n接下来，与大家，还有远在美国做 AI 博士后研究的 Alicia，一起开始我们的 60 天 Python 探索之旅吧。\n\n所有的这些考虑，都是为了让大家在短时间内掌握 Python 技术栈，多一个生存的本领。拿到理想的 Offer 后，早日过上自己想要的生活。\n\n让我们开始吧。\n\n如下，按照是否为静态/动态语言，弱类型/强类型两个维度，\n\n总结常用的语言分类。\n\n![image-20200205155429583](https://images.gitbook.cn/2020-02-05-080211.png) ### 四大基本语法\n\"\"\"\n```\n\n你可能很快写出如下的正则表达式：\n\n```\n# 元字符.表示匹配除\\n字符外的任意一个字符\n# 元字符*表示匹配前面一个原子0次或多次\npat = r'https:.*' \n```\n\n然后导入`re`模块，使用`findall`方法找出所有匹配：\n\n```python\nimport re\nresult = re.findall(pat,urls)\nprint(result)\n```\n\n运行结果显示如下，观察发现2个匹配，但是每个匹配链接都包括冗余字符，因此匹配错误：\n\n```\n['https://images.gitbook.cn\n/2020-02-05-014719.png)',\n\n'https://images.gitbook.cn\n/2020-02-05-080211.png) ### 四大基本语法']\n```\n\n我们再稍微优化原正则表达式为：\n\n```python\n# 添加 \\) 表示待匹配子串以右括号结尾\npat = r'https:.*\\)'\n```\n\n打印结果显示如下，结果确实好一点，但是依然包括右括号，结果还是错误的：\n\n```\n['https://images.gitbook.cn/\n2020-02-05-014719.png)', \n\n'https://images.gitbook.cn/\n2020-02-05-080211.png)']\n```\n\n所以掌握**提取**子串的技能就很重要，实现提取子串也很简单，只需把想要返回的子串加上一对括号就行，如下所示：\n\n```python\n# 把想要返回的子串外面添加一对括号\n\npat = r'(https:.*)\\)'\n```\n\n此时返回结果完全正确，无任何多余字符。想要返回的子串外面添加一对括号还有个专业叫法：**捕获**或**分组**。\n\n<center>[上一个例子](94.md)    [下一个例子](96.md)</center>"
  },
  {
    "path": "md/96.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/7/21\n```\n\n#### 96 贪心捕获和非贪心捕获\n\n捕获功能非常实用，使用它需要区分一点，贪婪捕获和非贪婪捕获。前者指在满足匹配模式前提下，返回包括尽可能多的字符匹配模式；后者指满足匹配条件下，尽可能少的捕获。\n\n我们伪造一个理想状况下的案例：\n\n```\nhtmlContent = \"\"\"\n        <div><div><h2>这是二级标题</h2></div><div><p> 这是一个段落>/p></div></div>\n\"\"\"\n```\n\n贪心捕获使用`(.*)`，如下所示：\n\n```\npat = r\"<div>(.*)</div>\"\n\nresult = re.findall(pat,htmlContent)\n```\n\n结果为如下，尽可能长的捕获，而不是遇到第一个`</div>`时就终止：\n\n```\n['<div><h2>这是二级标题</h2></div><div><p> 这是一个段落>/p></div>']\n```\n\n而非贪心捕获的正则表达式为`<div>(.*?)</div>\"`，如下：\n\n```\npat = r\"<div>(.*?)</div>\"\n\nresult = re.findall(pat,htmlContent)\n\nprint(result)\n```\n\n结果为两个元素，遇到第一个`</div>`时终止，然后继续捕获出第二子串：\n\n```\n['<div><h2>这是二级标题</h2>', \n  '<p> 这是一个段落>/p>']\n```\n\n以上例子仅仅用作演示两者区别，实际的html结构含有换行符等，环境比上面要复杂的多，贪心和非贪心捕获的写法可能不会导致结果不同，但是我们依然需要理解它们的区别。\n\n<center>[上一个例子](95.md)    [下一个例子](97.md)</center>"
  },
  {
    "path": "md/97.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/8/3\n```\n\n#### 97 使用正则做密码安全检查\n\n密码安全要求：\n\n1)要求密码为6到20位; \n\n2)密码只包含英文字母和数字\n\n```python\npat = re.compile(r'\\w{6,20}') # 这是错误的，因为\\w通配符匹配的是字母，数字和下划线，题目要求不能含有下划线\n# 使用最稳的方法：\\da-zA-Z满足`密码只包含英文字母和数字`\npat = re.compile(r'[\\da-zA-Z]{6,20}')\n```\n选用最保险的`fullmatch`方法，查看是否整个字符串都匹配：\n```python\npat.fullmatch('qaz12') # 返回 None, 长度小于6\npat.fullmatch('qaz12wsxedcrfvtgb67890942234343434') # None 长度大于22\npat.fullmatch('qaz_231') # None 含有下划线\npat.fullmatch('n0passw0Rd')\nOut[4]: <re.Match object; span=(0, 10), match='n0passw0Rd'>\n```\n\n<center>[上一个例子](96.md)    [下一个例子](98.md)</center>"
  },
  {
    "path": "md/98.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/8/8\n```\n\n#### 98 爬取百度首页标题\n\n```python\nimport re\nfrom urllib import request\n\n#爬虫爬取百度首页内容\ndata=request.urlopen(\"http://www.baidu.com/\").read().decode()\n\n#分析网页,确定正则表达式\npat=r'<title>(.*?)</title>'\n\nresult=re.search(pat,data)\nprint(result) <re.Match object; span=(1358, 1382), match='<title>百度一下，你就知道</title>'>\n\nresult.group() # 百度一下，你就知道\n```\n\n<center>[上一个例子](97.md)    [下一个例子](99.md)</center>"
  },
  {
    "path": "md/99.md",
    "content": "```markdown\n@author jackzhenguo\n@desc \n@date 2019/8/12\n```\n\n#### 99 批量转化为驼峰格式(Camel)\n\n数据库字段名批量转化为驼峰格式\n\n分析过程\n\n```python\n# 用到的正则串讲解\n# \\s 指匹配： [ \\t\\n\\r\\f\\v]\n# A|B：表示匹配A串或B串\n# re.sub(pattern, newchar, string): \n# substitue代替，用newchar字符替代与pattern匹配的字符所有.\n```\n\n\n\n```python\n# title(): 转化为大写，例子：\n# 'Hello world'.title() # 'Hello World'\n```\n\n\n\n```python\n# print(re.sub(r\"\\s|_|\", \"\", \"He llo_worl\\td\"))\ns = re.sub(r\"(\\s|_|-)+\", \" \",\n           'some_database_field_name').title().replace(\" \", \"\")  \n#结果： SomeDatabaseFieldName\n```\n\n\n\n```python\n# 可以看到此时的第一个字符为大写，需要转化为小写\ns = s[0].lower()+s[1:]  # 最终结果\n```\n\n \n\n整理以上分析得到如下代码：\n\n```python\nimport re\ndef camel(s):\n    s = re.sub(r\"(\\s|_|-)+\", \" \", s).title().replace(\" \", \"\")\n    return s[0].lower() + s[1:]\n\n# 批量转化\ndef batch_camel(slist):\n    return [camel(s) for s in slist]\n```\n\n测试结果：\n\n```python\ns = batch_camel(['student_id', 'student\\tname', 'student-add'])\nprint(s)\n# 结果\n['studentId', 'studentName', 'studentAdd']\n```\n\n<center>[上一个例子](98.md)    [下一个例子](100.md)</center>"
  },
  {
    "path": "md/batch.py",
    "content": "\"\"\"\n@author jackzhenguo\n@desc 批量生成模板文件\n@tag datetime file\n@version v1.2\n@date 2020/8/23\n\"\"\"\n\nimport os\nimport calendar\nfrom datetime import date,datetime\n\ndef getEverydaySince(year,month,day,n=10):\n    i = 0\n    _, days = calendar.monthrange(year, month)\n    while i < n: \n        d = date(year,month,day)    \n        if day == days:\n            month,day = month+1,0\n            _, days = calendar.monthrange(year, month)\n            if month == 13:\n                year,month = year+1,1\n                _, days = calendar.monthrange(year, month)\n        yield d\n        day += 1\n        i += 1\n\n\ndef batchCreate(ps='.md',start=100,n=100,path='.',year=2020,month=2,day=1):\n  \n    for i,day in zip(range(start,start+n),\\\n                     getEverydaySince(year,month,day,n) \\\n                    ):\n        with open(path+'/'+str(i)+ps,'w') as fw:\n            \n            fw.write(\"\"\"\n```markdown\n@author jackzhenguo\n@desc\n@tag\n@version \n@date {}\n```\n\t\t     \"\"\".format(datetime.strftime(day,'%Y/%m/%d'))\\\n\t\t     )\n            print(day)\n    print('done')\n"
  },
  {
    "path": "script/add_nav.py",
    "content": "# function: give each *.md example to a navigation in bottom of file\n# author: zhenguo\n# date: 2021.2.27\n# version: 1.0\n\nimport os\n\nfor file in os.listdir('../md'):\n    if os.path.splitext(file)[-1] == '.md':\n        with open('../md/' + file, 'a') as f:\n            file_name = os.path.splitext(file)[0]\n            try:\n                c = '\\n\\n<center>[上一个例子](%s.md)    [下一个例子](%s.md)</center>' % (str(int(file_name) - 1), str(int(file_name) + 1))\n                f.write(c)\n                print('文件%s写入成功' % (file,))\n            except:\n                print(ex)\n"
  }
]