笔记整理出处:廖雪峰教程java
datetime是Python处理日期和时间的标准库。python
datetime模块还包含一个datetime类,经过from datetime import datetime导入的才是datetime这个类。
若是仅导入import datetime,则必须引用全名datetime.datetime。
datetime.now()返回当前日期和时间,其类型是datetime。nginx
datetime的timestamp() 方法能够获取毫秒时间,可是须要注意:
Python的timestamp是一个浮点数。若是有小数位,小数位表示毫秒数。某些编程语言(如Java和JavaScript)的timestamp使用整数表示毫秒数,这种状况下只须要把timestamp除以1000就获得Python的浮点表示方法。算法
fromtimestamp(t)方法与上面的相反,能够把毫秒时间转换成 一个标准时间,这里一样注意,须要传入一个浮点的毫秒时间不要使用整型毫秒时间。spring
str转换为datetime编程
不少时候,用户输入的日期和时间是字符串,要处理日期和时间,首先必须把str转换为datetime。转换方法是经过datetime.strptime()实现,须要一个日期和时间的格式化字符串:json
>>> from datetime import datetime
>>> cday = datetime.strptime('2015-6-1 18:19:59', '%Y-%m-%d %H:%M:%S')
>>> print(cday)
2015-06-01 18:19:59复制代码
字符串'%Y-%m-%d %H:%M:%S'规定了日期和时间部分的格式。详细的说明请参考Python文档。
注意转换后的datetime是没有时区信息的。api
datetime加减浏览器
对日期和时间进行加减实际上就是把datetime日后或往前计算,获得新的datetime。加减能够直接用+和-运算符,不过须要导入timedelta这个类:安全
>>> from datetime import datetime, timedelta
>>> now = datetime.now()
>>> now
datetime.datetime(2015, 5, 18, 16, 57, 3, 540997)
>>> now + timedelta(hours=10)
datetime.datetime(2015, 5, 19, 2, 57, 3, 540997)
>>> now - timedelta(days=1)
datetime.datetime(2015, 5, 17, 16, 57, 3, 540997)
>>> now + timedelta(days=2, hours=12)
datetime.datetime(2015, 5, 21, 4, 57, 3, 540997)复制代码
可见,使用timedelta你能够很容易地算出前几天和后几天的时刻。
collections是Python内建的一个集合模块,提供了许多有用的集合类。
namedtuple是一个函数,它用来建立一个自定义的tuple对象,而且规定了tuple元素的个数,并能够用属性而不是索引来引用tuple的某个元素。
这样一来,咱们用namedtuple能够很方便地定义一种数据类型,它具有tuple的不变性,又能够根据属性来引用,使用十分方便。
典型使用:坐标点的定义:
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(1, 2)
>>> p.x
1
>>> p.y
2复制代码
使用list存储数据时,按索引访问元素很快,可是插入和删除元素就很慢了,由于list是线性存储,数据量大的时候,插入和删除效率很低。
deque是为了高效实现插入和删除操做的双向列表,适合用于队列和栈:
>>> from collections import deque
>>> q = deque(['a', 'b', 'c'])
>>> q.append('x')
>>> q.appendleft('y')
>>> q
deque(['y', 'a', 'b', 'c', 'x'])复制代码
deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就能够很是高效地往头部添加或删除元素,(猜想设计初衷和java中的linkList相似,弥补list的短板)。
使用dict时,若是引用的Key不存在,就会抛出KeyError。若是但愿key不存在时,返回一个默认值,就能够用defaultdict(一般咱们应该会使用这个dict,毕竟谁也不能保证是都每一个key都存在或者取以前去判断一次):
>>> from collections import defaultdict
>>> dd = defaultdict(lambda: 'N/A')
>>> dd['key1'] = 'abc'
>>> dd['key1'] # key1存在
'abc'
>>> dd['key2'] # key2不存在,返回默认值
'N/A'复制代码
注意默认值是调用函数返回的,而函数在建立defaultdict对象时传入。
除了在Key不存在时返回默认值,defaultdict的其余行为跟dict是彻底同样的。
使用dict时,Key是无序的。在对dict作迭代时,咱们没法肯定Key的顺序。
若是要保持Key的顺序,能够用OrderedDict:
>>> from collections import OrderedDict
>>> d = dict([('a', 1), ('b', 2), ('c', 3)])
>>> d # dict的Key是无序的
{'a': 1, 'c': 3, 'b': 2}
>>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
>>> od # OrderedDict的Key是有序的
OrderedDict([('a', 1), ('b', 2), ('c', 3)])复制代码
注意,OrderedDict的Key会按照插入的顺序排列,不是Key自己排序:
>>> od = OrderedDict()
>>> od['z'] = 1
>>> od['y'] = 2
>>> od['x'] = 3
>>> list(od.keys()) # 按照插入的Key的顺序返回
['z', 'y', 'x']复制代码
OrderedDict能够实现一个FIFO(先进先出)的dict,当容量超出限制时,先删除最先添加的Key
Counter是一个简单的计数器,例如,统计字符出现的个数:
>>> from collections import Counter
>>> c = Counter()
>>> for ch in 'programming':
... c[ch] = c[ch] + 1
...
>>> c
Counter({'g': 2, 'm': 2, 'r': 2, 'a': 1, 'i': 1, 'o': 1, 'n': 1, 'p': 1})复制代码
Counter实际上也是dict的一个子类,上面的结果能够看出,字符'g'、'm'、'r'各出现了两次,其余字符各出现了一次。
Python提供了一个struct模块来解决bytes和其余二进制数据类型的转换。
struct的pack函数把任意数据类型变成bytes:
>>> import struct
>>> struct.pack('>I', 10240099)
b'\x00\x9c@c'复制代码
pack的第一个参数是处理指令,'>I'的意思是:
>表示字节顺序是big-endian,也就是网络序,I表示4字节无符号整数。
后面的参数个数要和处理指令一致。
unpack把bytes变成相应的数据类型:
>>> struct.unpack('>IH', b'\xf0\xf0\xf0\xf0\x80\x80')
(4042322160, 32896)复制代码
根据>IH的说明,后面的bytes依次变为I:4字节无符号整数和H:2字节无符号整数。
Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。
咱们以常见的摘要算法MD5为例,计算出一个字符串的MD5值:
import hashlib
md5 = hashlib.md5()
md5.update('how to use md5 in python hashlib?'.encode('utf-8'))
print(md5.hexdigest())复制代码
计算结果以下:
d26a53750bc40b38b65a520292f69306
若是数据量很大,能够分块屡次调用update(),最后计算的结果是同样的:
import hashlib
md5 = hashlib.md5()
md5.update('how to use md5 in '.encode('utf-8'))
md5.update('python hashlib?'.encode('utf-8'))
print(md5.hexdigest())复制代码
试试改动一个字母,看看计算的结果是否彻底不一样。
比SHA1更安全的算法是SHA256和SHA512,不过越安全的算法不只越慢,并且摘要长度更长。
要注意摘要算法不是加密算法,不能用于加密(由于没法经过摘要反推明文),只能用于防篡改
Python的内建模块itertools提供了很是有用的用于操做迭代对象的函数。
首先,咱们看看itertools提供的几个“无限”迭代器:
>>> import itertools
>>> natuals = itertools.count(1)
>>> for n in natuals:
... print(n)
...
1
2
3
...复制代码
由于count()会建立一个无限的迭代器,因此上述代码会打印出天然数序列,根本停不下来,只能按Ctrl+C退出。
cycle()会把传入的一个序列无限重复下去:
>>> import itertools
>>> cs = itertools.cycle('ABC') # 注意字符串也是序列的一种
>>> for c in cs:
... print(c)
...
'A'
'B'
'C'
'A'
'B'
'C'
...复制代码
一样停不下来。
repeat()负责把一个元素无限重复下去,不过若是提供第二个参数就能够限定重复次数:
>>> ns = itertools.repeat('A', 3)
>>> for n in ns:
... print(n)
...
A
A
A复制代码
无限序列虽然能够无限迭代下去,可是一般咱们会经过takewhile()等函数根据条件判断来截取出一个有限的序列:
>>> natuals = itertools.count(1)
>>> ns = itertools.takewhile(lambda x: x <= 10, natuals)
>>> list(ns)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]复制代码
itertools提供的几个迭代器操做函数更加有用:
chain()
**chain()能够把一组迭代对象串联起来,造成一个更大的迭代器**:
~~~python
>>> for c in itertools.chain('ABC', 'XYZ'):
... print(c)复制代码
迭代效果:'A' 'B' 'C' 'X' 'Y' 'Z'
groupby()
groupby()把迭代器中相邻的重复元素挑出来放在一块儿:
>>> for key, group in itertools.groupby('AAABBBCCAAA'):
... print(key, list(group))
...
A ['A', 'A', 'A']
B ['B', 'B', 'B']
C ['C', 'C']
A ['A', 'A', 'A']复制代码
itertools模块提供的所有是处理迭代功能的函数,它们的返回值不是list,而是Iterator,只有用for循环迭代的时候才真正计算
contextlib中提供了可让普通方法使用with。。。as...:的调用
写try...finally很是繁琐。Python的with语句容许咱们很是方便地使用资源,而没必要担忧资源没有关闭,因此上面的代码能够简化为:
with open('/path/to/file', 'r') as f:
f.read()
并非只有open()函数返回的fp对象才能使用with语句。实际上,任何对象,只要正确实现了上下文管理,就能够用于with语句。
实现上下文管理是经过enter和exit这两个方法实现的。例如,下面的class实现了这两个方法:
class Query(object):
def __init__(self, name):
self.name = name
def __enter__(self):
print('Begin')
return self
def __exit__(self, exc_type, exc_value, traceback):
if exc_type:
print('Error')
else:
print('End')
def query(self):
print('Query info about %s...' % self.name)复制代码
这样咱们就能够把本身写的资源对象用于with语句:
with Query('Bob') as q:
q.query()复制代码
编写enter和exit仍然很繁琐,所以Python的标准库contextlib提供了更简单的写法,上面的代码能够改写以下:
from contextlib import contextmanager
class Query(object):
def __init__(self, name):
self.name = name
def query(self):
print('Query info about %s...' % self.name)
@contextmanager
def create_query(name):
print('Begin')
q = Query(name)
yield q
print('End')复制代码
@contextmanager这个decorator接受一个generator,用yield语句把with ... as var把变量输出出去,而后,with语句就能够正常地工做了:
with create_query('Bob') as q:
q.query()复制代码
不少时候,咱们但愿在某段代码执行先后自动执行特定代码,也能够用@contextmanager实现。例如:
@contextmanager
def tag(name):
print("<%s>" % name)
yield
print("</%s>" % name)
with tag("h1"):
print("hello")
print("world")复制代码
上述代码执行结果为:
<h1>
hello
world
</h1>复制代码
代码的执行顺序是:
with语句首先执行yield以前的语句,所以打印出h1;
yield调用会执行with语句内部的全部语句,所以打印出hello和world;
最后执行yield以后的语句,打印出h1。
所以,@contextmanager让咱们经过编写generator来简化上下文管理。
@closing
若是一个对象没有实现上下文,咱们就不能把它用于with语句。这个时候,能够用closing()来把该对象变为上下文对象。例如,用with语句使用urlopen():
from contextlib import closing
from urllib.request import urlopen
with closing(urlopen('www.python.org')) as page:
for line in page:
print(line)
closing也是一个通过@contextmanager装饰的generator,这个generator编写起来其实很是简单:
@contextmanager
def closing(thing):
try:
yield thing
finally:
thing.close()
它的做用就是把任意对象变为上下文对象,并支持with语句。
@contextlib还有一些其余decorator,便于咱们编写更简洁的代码。
urllib提供了一系列用于操做URL的功能。
urllib的request模块能够很是方便地抓取URL内容,也就是发送一个GET请求到指定的页面,而后返回HTTP的响应:
例如,对豆瓣的一个URLapi.douban.com/v2/book/212…
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'))复制代码
能够看到HTTP响应的头和JSON数据:
Status: 200 OK
Server: nginx
Date: Tue, 26 May 2015 10:02:27 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 2049
Connection: close
Expires: Sun, 1 Jan 2006 01:00:00 GMT
Pragma: no-cache
Cache-Control: must-revalidate, no-cache, private
X-DAE-Node: pidl1
Data: {"rating":{"max":10,"numRaters":16,"average":"7.4","min":0},"subtitle":"","author":["廖雪峰编著"],"pubdate":"2007-6","tags":[{"count":20,"name":"spring","title":"spring"}...}复制代码
若是咱们要想模拟浏览器发送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'))
这样豆瓣会返回适合iPhone的移动版网页:
...
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0">
<meta name="format-detection" content="telephone=no">
<link rel="apple-touch-icon" sizes="57x57" href="http://img4.douban.com/pics/cardkit/launcher/57.png" />
...复制代码
PIL:Python Imaging Library,已是Python平台事实上的图像处理标准库了。PIL功能很是强大,但API却很是简单易用。
因为PIL仅支持到Python 2.7,加上年久失修,因而一群志愿者在PIL的基础上建立了兼容的版本,名字叫Pillow,支持最新Python 3.x,又加入了许多新特性,所以,咱们能够直接安装使用Pillow。
安装Pillow
在命令行下直接经过pip安装:
$ pip install pillow
若是遇到Permission denied安装失败,请加上sudo重试。
若是遇到Permission denied安装失败,请加上sudo重试。
操做图像
来看看最多见的图像缩放操做,只需三四行代码:
from PIL import Image
# 打开一个jpg图像文件,注意是当前路径:
im = Image.open('test.jpg')
# 得到图像尺寸:
w, h = im.size
print('Original image size: %sx%s' % (w, h))
# 缩放到50%:
im.thumbnail((w//2, h//2))
print('Resize image to: %sx%s' % (w//2, h//2))
# 把缩放后的图像用jpeg格式保存:
im.save('thumbnail.jpg', 'jpeg')复制代码
其余功能如切片、旋转、滤镜、输出文字、调色板等包罗万象。
好比,模糊效果也只需几行代码:
from PIL import Image, ImageFilter
# 打开一个jpg图像文件,注意是当前路径:
im = Image.open('test.jpg')
# 应用模糊滤镜:
im2 = im.filter(ImageFilter.BLUR)
im2.save('blur.jpg', 'jpeg')复制代码