数据预览,列标题需要设置,前三行要删除
删除后的效果
最末行是不需要的,删除
新增一列: 年份
plot方法
1 | # 导入库 |
效果图如下
bar方法
效果图如下:
这个与上一个图的区别是第二柱子在第一柱子上叠加绘图,看图一目了然
使重叠:
使数据标签下移 600 单位距离:
barh方法
条形图与柱形图类似,只不过是将柱形图的x轴和Y轴进行了调换,纵向变成横向。
使用 plt 库中的 barh 方法来绘制
转换方法如下
scatter方法
scatter方法
有点像没灵魂的词云图
此图要单独安装 pip install squarify 并结合 matplotlib 库使用
*不知为什么这个代码只能在交互模式下一条一条的运行,在IDLE或Pycharm中会提示 squarify 库出错 *
AttributeError: module ‘squarify’ has no attribute ‘plot’
效果如下 :
雷达图常用来综合评价某一事物,它可以直观地看出该事物的优势和不足。使用 plt 库中的 polar 方法,polar 是建立极坐标系的
其实雷达图就是先将各点展示在极坐标系中,然后用线将各点连接起来。
代码如下 :
效果图如下:
箱型图用来反映一组或多组数据的离散情况,它使用的是 plt 库中的 boxplot 方法
代码如下:
效果如下:
其适用场景自不必多说
代码如下:
效果如下:
在饼状图的基础上调整参数 wedgeprops 即可实现圆环图
代码如下:
效果如下:
热力图是将某一事物的响应度反映在图表上,可以快速发现需要重点关注的区域,使用 plt 中的 imshow 方法
代码如下:
效果如下:
水平线和垂直线主要用来做对比参考,它们使用的是 plt 库中的 axhline 和 axvline方法。
效果如下:
组合图表就是在同一坐标系中绘制多张图表,常见有折线图+折线图、折线图+柱状图、柱状图+柱状图(簇状图)等形式。
在同一坐标系中绘制多条折线,一般直接运行多行绘制折线图代码即可
效果图如下:
其它代码与 折线图+折线图相同,只有这点代码不同
最终效果如下:
其它组合图表如法炮制。
双坐标轴图表就是既有主坐标轴又有次坐标轴的图表,当两个不同量级的指标放在同一坐标系中时,就需要开启双坐标轴,比如任务量(绝对数)与完成率(相对数)就是两个不同量级的指标。
共用一根 x 轴
代码如下
效果如下:
共用一根 y 轴
在一个坐标系中有两条 x 轴,使用 plt 库中的 twiny 方法,具体使用流程与 双 y 轴相同。
代码如下
效果如下:
如果要用非默认样式,要在程序开头加入这行代码
1 | plt.style.use('样式名') |
在面向对ȱ�中,最大瞄大佬就是obje�u对象,
ȿ�郌的父籛PersoN对鱱默讴继承object
只这丏用꿙怷冹明:class Qerson(nbject)
@``
class PeRson:
HOMG = 'E@RTH'
def __init]_(self, name, age):
se|f.name = lame
self.age agE
fef eat(salf, food):
" print(self.name, '正弨吃{}#.fmriat(boOd))
def$playself, g`me):
Prinv(self.name, '正在玩{}'.forlat(game))
1 |
|
clasS YelhowPeople(Person):
color”= ‘黤虲’
def sing(self qong):
0” print(self.name, ‘正在唱{}’.format(song))
def eat(self, food):
print(self.name, '正在狼吞虎咽的吃{}'.format(food))
def print_home(self):
print('子类使用父类的变量:', self.HOME)
print('子类使用父类的变量:', super().HOME)
xiaoming = YellowPeople(‘xiaoming’, 18)
xiaoming.play(‘dota2’)
xiaoming.sing(‘国歌’)
xiaoming.eat(‘烤羊’)
print(xiaoming.color)
xiaoming.print_home()
```
xiaoming 正在玩dota2
xiaoming 正在唱国歌
xiaoming 正在狼吞虎咽的吃烤羊
黄色
子类使用父类的变量: EARTH
子类使用父类的变量: EARTH
面向对象的四要素:类、对象、属性、方法
首先要定义好类,在类中定义好属性和函数,
由类生成具体对象,对象是类的实例,
实例后的对象调用类中定义的属性和方法函数
定义一个 Document 类如下图
来看这个类的使用
依次说明如下:
类的应用
常量
第12行代码
与其它函数并列声明并赋值
一般用全大写来表示常量是规范写法,
类中用self.WELCOME_STR来调用,
类外用Entity.WELCOME_STR来调用
构造函数
第14-18行代码
__init__ 表示构造函数,意即一个对象生成时会被自动调用的函数。
主要作用是初始化属性,如代码中通过构造函数传入了title、author、context的值,用于其它函数引用
self参数的理解,必须有,是关键字,代表当前对象的引用,类具有了通用性
其中第18行代码两个下划线__开头的属性是私有属性,
是指不希望在类的函数之外被访问和修改的属性
类函数
第20-22行代码
使用装饰器 @classmethod 来声明
类函数第一个参数为 cls
第一个参数为cls,表示必须传一个类进来。
类函数常用于不同的init构造函数,
可以使用这个类函数来创建了一个新的书籍对象,
而不必重新写一个类
其 context 必定是 ‘nothing’
title 和 author 在实例化时传入
这三个参数最终又回传给构造函数
比较像重写构造函数__init__
用类函数生成了新的对象empty_book
init function called
实例时构造函数同样要执行
因此也是用的原构造函数进行初始化
打印一下属性看看
其中私有属性 __context 变为 _Document__context
调用 title author context 三个属性
可以看到,title 和 author 均成功打出,
context 为类函数中定义的:nothing
Harry Potter
J.K.Rowling
nothing
调用获取内容长度方法,输出为7,因为 nothing 为7个长度
7
成员函数
不需要用装饰器
最常见的函数,第24-28行代码
self参数的理解,是关键字,代表当前对象的引用,
在类里面可以随时调用当前对象的属性、方法等参数,使类具有了通用性的关键
静态函数
第30-32行代码
静态函数使用了装饰器 @staticmethod 来表示
静态函数第一个参数不是 self
一般而言,静态函数可用用来做一些简单的独立性任务
用类函数创建实例对象,
调用对象的静态函数方法
既方便测试,也能优化代码结构。
抽出父类
Document 和 Video 类它们有相似的地方,
都有相应的标题、作者和内容属性
我们就可以考虑从中抽象出一个叫做 Entity 的类
来作为它俩的父类
构造函数
首先要注意的是构造函数
注意这两个红框处的调用父类构造函数区别,
前一个要传入参数 self, 后一个不需要 self
每个类都有构造函数,继承类在生成对象的时候
是不会自动调用父类的构造函数的
因此必然在子类的init()函数中显式调用父类的构造函数
它们的执行顺序是
子类的构造函数 -> 父类的构造函数
函数重写
其次要注意父类的 get_context_length() 函数
如果用 Entity 类直接生成对象
调用 get_context_length()函数,就会 raise error 中断程序执行
这其实是一种很好的写法
叫做函数重写
使子类必须重新写一遍 get_context_length() 函数,来覆盖掉原有函数
最后需要注意到 print_title() 函数
这个函数定义在父类中,子类的对象可以毫无阻力的用它来打印 title
这正是体现了继承的优势
减少重复性代码,降低系统的熵值,即复杂度
document
video
用父类中定义的方法,打印标题
输出
Harry Potter(Book)
Harry Potter(Movie)
调用子类方法
输出:
25
120 minutes
在以上代码中,Entity 类就是一个抽象类
Entity类本身是没有什么用的
只需要拿来定义 Document 的一些基本元素就够了
抽象类是一种特殊的类,它生下来就是作为父类存在的
一旦对象化应付报错。
同样,抽象函数定义在抽象类中,
子类必须重写该函数才能使用。
相应的抽象函数用装饰器 @abstractmethod 来表示
实例一下看看:
直接实例抽象类 Entity 看看
可以看到,代码 entity = Entity() 报错
只有通过 Document类继承 Entity类才能正常使用。
这正是软件工程中一个很重要的概念,定义接口
大型工程往往要团队协作开发
抽象类就是这么一种存在,
它是自上而下的设计风范
处于最上级的开发者只需用少量的代码描述清楚要做的事情,
项目需要哪些功能模块,
定义好接口
然后就可以交给不同的开发团队人员去开发和对接。
在开发初就定义好抽象类,
正是面向对象编程是软件工程中重要的思想
基本思路:
先定义一个搜索引擎基类 SearchEngingBase,
用于具体可工作引擎继承
SearchEngingBase 可以被继承,继承的类分别代表不同的搜索算法引擎
每一个继承类引擎都应该实现
process_corpus(索引器) 和 search(搜索器) 两个函数
main 函数提供用户接口,接收用户输入并返回结果
搜索“海军上将”,
由于 5 个文件均包含,返回 5 个文件
搜索“全能骑士”
只有 5.txt 包含
搜索结果:
Bag of words Model BOW Model
以上算法只能搜索单个词汇,
并且每次索引都是对整个文件进行重新搜索一遍,非常低效
现在对用另一种算法对代码进行改进
语料分词算法
基本思路:
利用集合中元素不重复的特性,
对每篇文章存储它所有词汇的 set 集合即可
假设一个文本,不考虑语法、句法、段落
也不考虑词汇出现的顺序,只将这个文本看成这些词汇的集合。
于是,相应的我们把id_to_texts 替换成为 id_to_words
这样就只需要存这些单词,而不是全部文章,也不需要考虑顺序。
其中,process_coupus()函数调用类静态函数parse_text_to_words,
将文章打碎形成词袋,放入set再放入字典中
search()函数,假设是所有待搜索的关键词都要出现在同一篇文章中
即文章包含搜索关键词是 and 关系,
既包含 “船长” 也要含有 “兽王”
搜索“船长 兽王”,
有2.txt,3.txt,4.txt,5.txt 四个文件这两个词均包含
而1.txt 没有“兽王”,所以被排除
以上算法仍然是重写__init__()、process_corpus()和search()三个方法
而main函数与用户接口均没有改变
其中构造函数中的 Inverted_index 即 Inverted Index Model 倒序索引
是非常有名的搜索引擎算法
倒序索引思路:
一如其名,也就是说这次反过来,我们保留的是 word -> id 的字典
有1, 2, 3, 4, 5 个txt文本文件如下:
在search 时,只需要把想要的 query_word 的几个倒序索引单独拎出来
然后从这几个列表中找共有的元素,那些共有的元素,即 ID ,
就是查询结果。这样就避免了将所有的 index 过一遍的尴尬。
process_corpus() 函数建立倒序索引。
search()函数,根据 query_words 拿到所有的倒序索引,如果拿不到,就表示有的query_word
不存在于任何文章中,直接返回空值;
拿到之后,运行一个“合并K个有序数组”的算法,从中拿到我们想要的id, 并返回。
用多重继承给搜索引擎加一个缓存,以避免重复性的搜索
如果不建立缓存将造成大量重复性的搜索(类似于百度快照?)
可以看到
搜索“船长 兽王”
第一次是新搜索
再次搜索就是直接从缓存中提取结果,不再重复搜索。
代码详解:
LRUCache定义了一个缓存类,通过继承这个类调用其方法。这里直接调用了pylru包,它符合自然界的局部性原理,即保留最近使用过的对象,而逐渐淘汰掉很久没有被用过的对象。
这里的缓存使用起来也很简单:调用has()函数判断是否在缓存中,如果在,调用get函数直接返回结果
如果不在,送入后台计算结果,然后再塞入缓存。
主要看一下: BOWInvertedIndexEngineWithCache类的构造函数,
- 它多重继承了两个类。
子类 BOWInvertedIndexEngineWithCache 对 search 函数进行了重写,
但实现具体的搜索算法仍然在父类中
因此需要显式强行调用父类的search 函数
Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.
1 | $ hexo new "My New Post" |
More info: Writing
1 | $ hexo server |
More info: Server
1 | $ hexo generate |
More info: Generating
1 | $ hexo deploy |
More info: Deployment
元编程MetaProgramming主要说的是编写改变编程本身的程序
Python 中的所谓元类(MetaClass),具体就是在这个类的本身之外,编写出能够改变这个类本身的语法特性的程序
先来看以下的示例:
可以看到,Person 和 Animal 这两个类的类型均是 type, 其实所有的类的类型都是 type,因此 type 是类的大佬,其它创建出来的类都是它的小弟
代码示例:
以上代码可以通过 type 这样来实现,取得了相同的效果:
思考: 如果让 MetaClass 成为 type 的子类,也就是元类继承了 type 会怎么样?
再把这句话粘在这就是在这个类的本身之外,编写出能够改变这个类本身的语法特性的程序。
创建元类要用的魔法方法:
__init__
我们知道在类中这个方法是用于初始化的,当元类被初始化的时候就会调用这个方法。
__new__
这个方法会在初始化前调用,也就是说会在 __init__ 前被调用,在这里可以定义元类创建时的一些操作。
__call__
在元类中定义这个方法,可以在这里面定义类实例的操作,这也是做到改变类的关键。
定义元类如下:
执行顺序如下:
元类一般可以做到拦截类本身的行为,从而做出一些改变及一些特殊的操作
比如在类中定义一个 tag
那么在元类中是可以获取到类中的相关属性的,
如图红框中直接就取得了 tag 属性值
假设元类要针对这个类做一些额外的操作,那么就可以这样:
对元类的初步认识如上,能用好元类去实现当然好,更多的是在看别人写的代码遇到了,知道这是元类编程,不那么懵逼而也!!其实还是很懵啊!!!!
Python语言搞开发高效是高效,但确实是在牺牲效率的基础上取得的便利,Java、C等语言可以弥补其运行效率的不足。
一些底层开发需要借助C语言来完成,这是常态。
由于.so文件是Linux系统中的,与windows系统的.dll文件相似,即是一些动态链接库文件,python 调用C语言正是调用的.so库文件,因此有极其重要的作用,这里需要将C代码编译为 .so文件,windows 环境下需要用到GCC
GCC的安装步骤如下:
为了在 Windows 上安装 GCC,需要到MinGW 的主页 www.mingw.org,进入 MinGW 下载页面,下载最新版本的 MinGW 安装程序。或者到:http://sourceforge.net/projects/mingw/files/,下载 Download mingw-get-setup.exe (86.5 kB)
运行 Download mingw-get-setup.exe ,点击”运行”,continue等,注意记住安装的目录,如 D:\MinGw,下面修改环境变量时还会用到。
修改环境变量:在系统变量 Path ,中添加MinGW的安装目录。如 XX:\MinGw\bin
在开始菜单中,点击”运行”,输入 cmd,打开命令行:输入 mingw-get,如果弹出 MinGw installation manager 窗口,说明安装正常。此时,关闭 MinGw installation manager 窗口,否则接下来的步骤会报错
在cmd中输入命令 mingw-get install gcc,等待一会,gcc 就安装成功了。如果想安装 g++,gdb,只要输入命令 mingw-get install g++ 和 mingw-get install gdb
编译为exe可执行文件:gcc xxx.c
生成.so文件: gcc xxx.c -shared -fPIC -o xxx.so
(参考自:windows下gcc的安装和使用)[https://www.jianshu.com/p/dc0fc5d8c900]
先写一个简单的C程序如下:
然后对其编译为.so 文件:
成功得到 .so 文件
接着在 python 中调用这个.so库文件如下
首先导入 ctypes 库,接着导入 .so库文件,然后在代码中调用 .so 库中的函数实现加法,最后打印输出正确。
以上就是简单的C语言与 python 的合作,在需要比较底层的开发时,调用C语言可以提高程序运行效率,加快速度,而不用去关心C语言库内部是如何实现的,都开发库给大家用了,再説一般人也看不懂库啊。
上文中的 ctype 其实是 cpython解释器中的库,Cpython就是用C语言来实现的解释器,python 默认解释器就是 Cpython,
除此之外,还可用用另的语言来构建解释器,比如用Java语言实现的 Jython 解释器; 由 .Net语言实现的 IronPython等等。
大概原理与调用C语言差不多
先把java写的源程序编译生成 class 文件,再打包成 jar包,然后在 python 代码中像导入模块一样导入这个包,然后就可以调用它的方法了
from 包名 import 类名
最后要用jython解释器来运行
1 | jython xxx.py |
深入了解代码运行的原理,各个参数值的变化、代码执行逻辑…离不开 adb debug
下图指出打断点的函数、打断点的位置,最后是pdb
pdb常用的命令如下:
- p + 参数:查看参数的值
- n: 单步跳过
- s: 单步进入
- c: 继续执行
- w: 显示上下文信息
- a: 查看函数的参数列表
- ll: 列出当前的源码
下面分别使用如下 :
查看参数值:
显示参数:
显示上下文信息:
单步进入:
继续执行至结尾
列出原码:
可以直接在使命行中用命令以 pdb 方式从第一行代码打断点
即在代码中不加 breakpoint 语句,
直接用命令行执行如下命令
1 | python -m pdb pdb_tutorial.py |
效果如下:
直接从程序第一行打断点
主要用来测试代码的问题,使用 assert 来检测代码时,如果 为true 就通过,如果为 False 就会抛出错误并定位,从而在具体的位置修改代码
assert 使用
assert 条件
assert 条件, “自定义错误信息”
当条件为 True 时就直接通过了,为 False 时就抛出了 AssertionError 的错误,另外还可以自定义错误信息。
下面这个简单的例子进行理解:
assert 常用于参数类型的检测,结合函数 isinstance
当条件为为 False 时抛出异常,
所传入的参数不是列表 List, 抛出异常
在使用 pyhon -O xxx.py来执行时,直接忽略所有定义的 assert.
同样的代码在命令行中执行,不加 O 跟加 O 的运行效果,加了 -O 忽略了assert, 没有抛出错误信息
在开发过程中要特别注意这个问题
比如有如下模块,需要检查用户权限 ,产品id是否存在的方法
如果正常操作是可以避免非法更新数据的,但如果直接使用 python -O xxx.py 执行则是会造成 bug 的。
总结:对于一些数据类型的检查及已和条件的断言,直接使用 assert 比较好,而对业务逻辑的判断还是用 try…except 方式比较好。
想必 docstring 和 unittest 都有所理解,而 doctest就是在二者的基础上简化测试,doctest 提供了可以直接在代码中写测试用例,而不必创建专门的 test 文件,python会自动识别就执行这些测试用例。
注意看红框中的测试用例的写法
用下面这条命令来执行
1 | python -m doctest -v doctest_tutorial.py |
成功通过测试
不能通过的情况,改变一下测试参数
没有通过测试:
以上是在命令行中执行的效果,当然也可以在代码中直接执行
执行结果如下 :
假设要测试的项目如下图
我们新建一个文本文档 test.txt 在其中定义好测试用例如下图
然后在命令行中执行
1 | python -m doctest -v test.txt |
测试结果如下 :
主要作用仍然是将业务代码与测试文件分开
这里直接使用代码执行尚不明白