若想技术精进,当然得把基础知识打得牢牢的。
廖雪峰的官方网站 python3教程,该网站提供的教程浅显易懂,还附带了讲学视频,非常适合初学者正规入门。
以下是通过廖雪峰python官方网站学习的个人查漏补缺。
主要内容包括:1.常用内置模块【1)datatime时间、2)collections集合、3)Base64表示二进制、4)struct转换bytes和二进制、5)hashlib提供常见摘要算法、6)hmac算法、7)itertools操作迭代对象、8)contextlib装饰器、9)urllib、10)XML、11)HTMLParser】 2.常用第三方模块【1)Pillow处理图片的模块、2)requests访问url资源的模块、3)chardet解决字符串编码问题的模块、4)psutil方便日常运维的模块、5)virtualenv创建隔离的python运行环境的模块】 3.图形界面
1.常用内置模块 --介绍11个
内置模块:即python中无需额外安装和配置,即可直接使用。
1)datatime:datetime是Python处理日期和时间的标准库。
获取当前时间和指定时间
timestamp:在计算机中,时间实际上是用数字表示的。我们把1970年1月1日 00:00:00 UTC+00:00时区的时刻称为epoch time,记为0(1970年以前的时间timestamp为负数),当前时间就是相对于epoch time的秒数,称为timestamp。可见timestamp的值与时区毫无关系,因为timestamp一旦确定,其UTC时间就确定了,转换到任意时区的时间也是完全确定的,这就是为什么计算机存储的当前时间是以timestamp表示的,因为全球各地的计算机在任意时刻的timestamp都是完全相同的(假定时间已校准)。
datetime与timestamp相互转换的方法
注意Python的timestamp是一个浮点数。如果有小数位,小数位表示毫秒数。timestamp也可以直接被转换到UTC标准时区的时间。
str与datetime相互转换的方法
datetime加减
datetime表示的时间需要时区信息才能确定一个特定的时间,否则只能视为本地时间。如果要存储datetime,最佳方法是将其转换为timestamp再存储,因为timestamp的值与时区完全无关。
2)collections:collections是Python内建的一个集合模块,提供了许多有用的集合类。
namedtuple:定义类似 point(x,y),circle(x,y,r)的数据类型,使用namedtuple非常方便。
namedtuple('名称',[属性list])
namedtuple方法的用法格式
deque:使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:
deque双向列表
deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就可以非常高效地往头部添加或删除元素。
defaultdict:使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict:
defaultdict默认字典
除了在Key不存在时返回默认值,defaultdict的其他行为跟dict是完全一样的。
OrderedDict:使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。如果要保持Key的顺序,可以用OrderedDict:
OrderedDict有序的字典
OrderedDict(因为它可以保留插入时的顺序)可以实现一个FIFO(先进先出)的dict,当容量超出限制时,先删除最早添加的Key:
用OrederDict实现先进先出操作
关于OrderedDict排序:>>> from collections import OrderedDict
>>> d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2
#按key排序,自行设置reverse
>>>OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple',4), ('banana', 3), ('orange', 2), ('pear', 1)])
#按value排序
,自行设置reverse
>>>OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear',1), ('orange', 2), ('banana', 3), ('apple', 4)])
#按key的长度排序
,自行设置reverse
>>>OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
OrderedDict([('pear',1), ('apple', 4), ('orange', 2), ('banana', 3)])
Counter:Counter是一个简单的计数器,例如,统计字符出现的个数:
Counter实际上也是dict的一个子类
用记事本打开exe、jpg、pdf这些文件时,我们都会看到一大堆乱码,因为二进制文件包含很多无法显示和打印的字符,所以,如果要让记事本这样的文本处理软件能处理二进制数据,就需要一个二进制到字符串的转换方法。Base64是一种最常见的二进制编码方法。
Base64原理
base64简单操作
Base64是一种通过查表的编码方法,不能用于加密,即使使用自定义的编码表也不行。Base64适用于小段内容的编码,比如数字证书签名、COOKIE的内容等。Base64是一种任意二进制到文本字符串的编码方法,常用于在URL、COOKIE、网页中传输少量二进制数据。
准确地讲,Python没有专门处理字节的数据类型。但由于b'str'可以表示字节,所以,字节数组=二进制str。而在C语言中,我们可以很方便地用struct、union来处理字节,以及字节和int,float的转换。好在Python提供了一个struct模块来解决bytes和其他二进制数据类型的转换。
5)hashlib:Python的hashlib提供了常见的摘要算法【摘要算法又称哈希算法、散列算法,它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)】,如MD5,SHA1等等。
举个例子,你写了一篇文章,内容是一个字符串'how to use python hashlib - by Michael',并附上这篇文章的摘要是'2d73d4f15c0db7f5ecb321b6a65e5d6d'。如果有人篡改了你的文章,并发表为'how to use python hashlib - by Bob',你可以一下子指出Bob篡改了你的文章,因为根据'how to use python hashlib - by Bob'计算出的摘要不同于原始文章的摘要。可见,摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest,目的是为了发现原始数据是否被人篡改过。摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数,计算f(data)很容易,但通过digest反推data却非常困难。而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同。
MD5是最常见的摘要算法,速度很快,生成结果是固定的128 bit字节,通常用一个32位的16进制字符串表示。SHA1的结果是160 bit字节,通常用一个40位的16进制字符串表示。比SHA1更安全的算法是SHA256和SHA512,不过越安全的算法不仅越慢,而且摘要长度更长。
摘要算法应用:
任何允许用户登录的网站都会存储用户登录的用户名和口令。如何存储用户名和口令呢?方法是存到数据库表中。正确的保存口令的方式是不存储用户的明文口令,而是存储用户口令的摘要,比如MD5。当用户登录时,首先计算用户输入的明文口令的MD5,然后和数据库存储的MD5对比,如果一致,说明口令输入正确,如果不一致,口令肯定错误。
摘要算法在很多地方都有广泛的应用。要注意摘要算法不是加密算法,不能用于加密(因为无法通过摘要反推明文),只能用于防篡改,但是它的单向计算特性决定了可以在不存储明文口令的情况下验证用户口令。
6)hmac:Hmac算法针对所有哈希算法都通用。
Hmac算法:Keyed-Hashing for Message Authentication。它通过一个标准算法,在计算哈希的过程中,把key混入计算过程中。
7)itertools:Python的内建模块itertools提供了非常有用的用于操作迭代对象的函数。
itertools提供的几个“无限”迭代器(for循环时,根本停不下来):>>> import itertools
>>> natuals = itertools.count(1) #count()会创建一个无限的迭代器
>>> cs = itertools.cycle('ABC') # 注cycle()会把传入的一个序列无限重复下去
>>> ns = itertools.repeat('A', 3) #repeat()负责把一个元素无限重复下去,不过如果提供第二个参数就可以限定重复次数
无限序列虽然可以无限迭代下去,但是通常我们会通过takewhile()等函数根据条件判断来截取出一个有限的序列:
chain():可以把一组迭代对象串联起来,形成一个更大的迭代器:
groupby():把迭代器中相邻的重复元素挑出来放在一起:
实际上挑选规则是通过函数完成的,只要作用于函数的两个元素返回的值相等,这两个元素就被认为是在一组的,而函数返回值作为组的key。如果我们要忽略大小写分组,就可以让元素'A'和'a'都返回相同的key:
itertools模块提供的全部是处理迭代功能的函数,它们的返回值不是list,而是Iterator,只有用for循环迭代的时候才真正计算。
8)contextlib:@contextlib还有一些其他decorator,便于我们编写更简洁的代码。
正确关闭文件资源的一个方法是使用try...finally。写try...finally非常繁琐。Python的with语句允许我们非常方便地使用资源,而不必担心资源没有关闭。并不是只有open()函数返回的fp对象才能使用with语句。实际上,任何对象,只要正确实现了上下文管理,就可以用于with语句。实现上下文管理是通过__enter__和__exit__这两个方法实现的。
@contextmanager:编写__enter__和__exit__仍然很繁琐,因此Python的标准库contextlib提供了更简单的写法:
@contextmanager这个decorator接受一个generator,用yield语句把with ... as var把变量输出出去,然后,with语句就可以正常地工作了。
@closing:如果一个对象没有实现上下文,我们就不能把它用于with语句。这个时候,可以用closing()来把该对象变为上下文对象。例如,用with语句使用urlopen():
9)urllib:urllib提供了一系列用于操作URL的功能。
Get:urllib的request模块可以非常方便地抓取URL内容,也就是发送一个GET请求到指定的页面,然后返回HTTP的响应。from urllib import request
with request.urlopen('https://api.douban.com/v2/book/2129650') as f:
data = f.read()
print('Status:', f.status, f.reason)
for k, v in f.getheaders():
print('%s: %s' % (k, v))
print('Data:', data.decode('utf-8'))
如果我们要想模拟浏览器发送GET请求,就需要使用Request对象,通过往Request对象添加HTTP头,我们就可以把请求伪装成浏览器。例如,模拟iPhone 6去请求豆瓣首页:from urllib import request
req = request.Request('http://www.douban.com/')
req.add_header('User-Agent', 'Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25')
with request.urlopen(req) as f:
print('Status:', f.status, f.reason)
for k, v in f.getheaders():
print('%s: %s' % (k, v))
print('Data:', f.read().decode('utf-8'))
Post:如果要以POST发送一个请求,只需要把参数data以bytes形式传入。我们模拟一个微博登录,先读取登录的邮箱和口令,然后按照weibo.cn的登录页的格式以username=xxx&password=xxx的编码传入:
Handler:如果还需要更复杂的控制,比如通过一个Proxy去访问网站,我们需要利用ProxyHandler来处理proxy_handler = urllib.request.ProxyHandler({'http': 'http://www.example.com:3128/'})
proxy_auth_handler = urllib.request.ProxyBasicAuthHandler()
proxy_auth_handler.add_password('realm', 'host', 'username', 'password')
opener = urllib.request.build_opener(proxy_handler, proxy_auth_handler)
with opener.open('http://www.example.com/login.html') as f:
pass
urllib提供的功能就是利用程序去执行各种HTTP请求。如果要模拟浏览器完成特定功能,需要把请求伪装成浏览器。伪装的方法是先监控浏览器发出的请求,再根据浏览器的请求头来伪装,User-Agent头就是用来标识浏览器的。
10)XML:解析XML。
XML虽然比JSON复杂,在Web中应用也不如以前多了,不过仍有很多地方在用,所以,有必要了解如何操作XML。
DOM vs SAX
操作XML有两种方法:DOM和SAX。DOM会把整个XML读入内存,解析为树,因此占用内存大,解析慢,优点是可以任意遍历树的节点。SAX是流模式,边读边解析,占用内存小,解析快,缺点是我们需要自己处理事件。正常情况下,优先考虑SAX,因为DOM实在太占内存。在Python中使用SAX解析XML非常简洁,通常我们关心的事件是start_element,end_element和char_data,准备好这3个函数,然后就可以解析xml了。
举个例子,当SAX解析器读到一个节点时:python
会产生3个事件:
1.start_element事件,在读取时;
2.char_data事件,在读取python时;
3.end_element事件,在读取时。
解析XML时,注意找出自己感兴趣的节点,响应事件时,把节点数据保存起来。解析完毕后,就可以处理数据。
11)HTMLParser:解析HTML。
HTML本质上是XML的子集,但是HTML的语法没有XML那么严格,所以不能用标准的DOM或SAX来解析HTML。好在Python提供了HTMLParser来非常方便地解析HTML。利用HTMLParser,可以把网页中的文本、图像等解析出来。
2.常用第三方模块
第三方模块:一般都是需要pip install 安装的模块。
1)Pillow:对图像进行操作的模块。安装了Anaconda就自带了该模块。
其他功能如切片、旋转、滤镜、输出文字、调色板等一应俱全。比如,模糊效果也只需几行代码:
模糊的代码
模糊的效果
PIL提供了操作图像的强大功能,可以通过简单的代码完成复杂的图像处理。
2)requests:处理URL,用于访问网络资源的模块。安装了Anaconda就自带了该模块。
通过GET访问一个页面>>> import requests
>>> r = requests.get('https://www.douban.com/') # 通过GET访问一个页面(豆瓣首页)
>>> r.text
对于带参数的URL,传入一个dict作为params参数>>> r = requests.get('https://www.douban.com/search', params={'q': 'python', 'cat': '1001'})
>>> r.url # 实际请求的URL
'https://www.douban.com/search?q=python&cat=1001'
requests的方便之处还在于,对于特定类型的响应,例如JSON,可以直接获取:>>> r = requests.get('https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20%3D%202151330&format=json')
>>> r.json()
{'query': {'count': 1, 'created': '2017-11-17T07:14:12Z', ...
需要传入HTTP Header时,我们传入一个dict作为headers参数>>> r = requests.get('https://www.douban.com/',headers={'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit'})
>>> r.text
要发送POST请求,只需要把get()方法变成post(),然后传入data参数作为POST请求的数据:>>> r = requests.post('https://accounts.douban.com/login',data={'form_email': 'abc@example.com', 'form_password': '123456'})
requests对COOKIE做了特殊处理,使得我们不必解析COOKIE就可以轻松获取指定的COOKIE:>>> r.COOKIEs['ts']
'example_COOKIE_12345'
要在请求中传入COOKIE,只需准备一个dict传入COOKIEs参数:>>> cs = {'token': '12345', 'status': 'working'}
>>> r = requests.get(url, COOKIEs=cs)
最后,要指定超时,传入以秒为单位的timeout参数:>>> r = requests.get(url, timeout=2.5) # 2.5秒后超时
3)chardet:解决字符串编码问题的模块。安装了Anaconda就自带了该模块。
其实现在python,在读写文件的时候每次都带上encoding='utf-8',基本上就能避开大部分的字符编码错误。
使用chardet可以检测编码:>>> chardet.detect(b'Hello, world!')
{'encoding': 'ascii', 'confidence': 1.0, 'language': ''}
检测GBK编码的中文:>>> data = '离离原上草,一岁一枯荣'.encode('gbk')
>>> chardet.detect(data)
{'encoding': 'GB2312', 'confidence': 0.7407407407407407, 'language': 'Chinese'}
检测的编码是GB2312,注意到GBK是GB2312的超集,两者是同一种编码,检测正确的概率是74%,language字段指出的语言是'Chinese'。对UTF-8编码进行检测:
>>> data = '离离原上草,一岁一枯荣'.encode('utf-8')
>>> chardet.detect(data)
{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}
对日文进行检测:
>>> data = '最新の主要ニュース'.encode('euc-jp')
>>> chardet.detect(data)
{'encoding': 'EUC-JP', 'confidence': 0.99, 'language': 'Japanese'}
可见,用chardet检测编码,使用简单。获取到编码后,再转换为str,就可以方便后续处理。chardet支持检测的编码列表请参考官方文档Supported encodings。
其实在Liunx服务器上top命令够用。
virtualenv为应用提供了隔离的Python运行环境,解决了不同应用间多版本的冲突问题。
3.图形界面
Python支持多种图形界面的第三方库,包括:Tk、wxWidgets、Qt、GTK等等。但是Python自带的库是支持Tk的Tkinter,使用Tkinter,无需安装任何包,就可以直接使用。
第一个GUI程序:
在GUI中,每个Button、Label、输入框等,都是一个Widget。Frame则是可以容纳其他Widget的Widget,所有的Widget组合起来就是一棵树。
pack()方法把Widget加入到父容器中,并实现布局。pack()是最简单的布局,grid()可以实现更复杂的布局。
在createWidgets()方法中,我们创建一个Label和一个Button,当Button被点击时,触发self.quit()使程序退出。
第三步,实例化Application,并启动消息循环:
在windows上运行得到的简陋结果,跟Java的图形界面设计很相似
GUI程序的主线程负责监听来自操作系统的消息,并依次处理每一条消息。因此,如果消息处理非常耗时,就需要在新线程中处理。
对这个GUI程序改进一下,加入一个文本框,让用户可以输入文本,然后点按钮后,弹出消息对话框。
当用户点击按钮时,触发hello(),通过self.nameInput.get()获得用户输入的文本后,使用tkMessageBox.showinfo()可以弹出消息对话框。Python内置的Tkinter可以满足基本的GUI程序的要求,如果是非常复杂的GUI程序,建议用操作系统原生支持的语言和库来编写。