datetime
%y:两位数的年份表示(00-99) %Y:四位数的年份表示(000-999)
%m:月份(01-12) %d:月内中的一天(0-31) %H:24小时制小时数(01-12) %I:12小时制小时数(01-12) %M:分钟数(00-59) %s:秒(00-59)
%a:本地简化星期名称 %A:本地完整星期名称 %b:本地简化月份名称 %B:本地完整月份名称 %c:本地相应的日期表示和时间表示
%j:年内的一天(001-366) %p:本地A.M.或P.M.的等价符 %U:一年中的星期数(00-53)星期天为星期的开始 %w:星期(0-6),星期天为星期的开始
%W:一年中的星期数(00-53)星期一为星期的开始 %x:本地相应的日期表示 %X:本地相应的时间表示 %Z:当前时区的名称 %%:%本身
datetime是python处理日期和时间的标准库
获取当前日期和时间
from datetime import datetime #datetime是模块,datetime模块还包含一个datetime类, #通过from datetime import datetime导入的才是datetime这个类,如果仅导入import datetime,则必须引用全名datetime.datetime now = datetime.now()#获取当前datetime print(now) print(type(now))
2019-12-10 11:43:15.034663 <class 'datetime.datetime'>
获取指定日期和时间
from datetime import datetime dt = datetime(2015,4,19,12,20) #用指定日期时间创建datetime print(dt)
datetime转换成timestamp
在计算机中,时间实际上是用数字表示的,把1970年1月1日00:00:00 UTC+00:00时区的时刻称为epoch time,记为0(1970年以前的时间timestamp为负数),当前时间就是相对于epoch time的秒数,称为timestamp
可以认为
timestamp = 0 = 1970-1-1 00:00:00 UTC+0:00
对应的北京时间是:
timestamp = 0 = 1970-1-1 08:00:00 UTC+8:00
可见timestamp的值与时区毫无联系,因为timestamp一旦确定,其UTC时间就确定了,转换到任意时区的时间也是完全正确的,这就是为什么计算机存储的当前时间是以timestamp表示的,因为全球各地的计算机在任意时刻的timestamp都是完全相同的(假定时间已校准)
把一个datetime类型转换为timestamp只需要简单调用timestamp()方法
from datetime import datetime dt = datetime(2015,4,19,12,20) #用指定日期时间创造datetime dt.timestamp() #把datetime转换成timestamp
1429417200.0
注意python的timestamp是一个浮点数,如果有小数位,小数位表示毫秒数
某些编程语言(如java和javascript)的timestamp使用整数表示毫秒数,这种情况下,只需要把timestamp除以1000就得到python的浮点表示方法
timestamp转换成datetime
要把timestamp转换成datetime,使用datetime提供的fromtimestamp()方法:
from datetime import datetime t = 1429417200.0 print(datetime.fromtimestamp(t))
2015-04-19 12:20:00
注意到timestamp是一个浮点数,它没有时区的概念,而而datetime是有时区的,上述转换是在timestamp和本地时间做转换
本地时间是指当前操作系统设定的时区,例如北京时区是东8区,则本地时间:2015-4-19 12:20:00实际上就是UTC+8:00时区的时间:215-04-19 12:20:00 UTC+8:00
而此刻的格林威治标准时间与北京相差了8小时,也就是UCT+0:00时区的时间应该是:2015-04-19 04:20:00 UTC+0:00
timestamp也可以直接被转换到UTC标准时区的时间
from datetime import datetime t = 1429417200.0 print(datetime.fromtimestamp(t)) #本地时间 print(datetime.utcfromtimestamp(t)) #UTC时间
2015-04-19 12:20:00 2015-04-19 04:20:00
str转换为datetime
用户输入的日期和时间是字符串,要处理日期和时间,首先必须把str转换成datetime,转换方法是通过datetime.strptime()实现,需要一个日期和时间的格式化字符串
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
转换后的datetime是没有时区信息的
datetime转换为str
如果已经有了datetime对象,要把它格式化为字符串显示给用户就需要转换为str,转换方法是通过strftime()实现的,同样需要一个日期和时间的格式化字符串
from datetime import datetime now = datetime.now() print(now) print(now.strftime('%a,%b %d %H:%M'))
2019-12-10 14:53:56.243806 Tue,Dec 10 14:53
datetime加减(timedelta)
from datetime import datetime,timedelta now = datetime.now() print(now) datetime(2015,5,18,16,57,3,540997) print(now+timedelta(hours = 10)) print(now-timedelta(days = 1)) print(now+timedelta(days = 2,hours = 12))
2019-12-10 15:09:23.538844 2019-12-11 01:09:23.538844 2019-12-09 15:09:23.538844 2019-12-13 03:09:23.538844
collections
namedtuple
#表示一个坐标 from collections import namedtuple Point = namedtuple('Point',['x','y']) p = Point(1,2) p.x #1 p.y #2
namedtuple是一个函数,它用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,并可以用属性而不是索引来引用tuple的某个元素,这样一来,用namedtuple可以很方便的定义一种数据类型,它具备tuple的不变性,又可以根据属性来引用,使用十分方便
namedtuple比普通tuple具有更好的可读性,可以使代码更易维护,同时与字典相比,又更加的轻量和高校,但是,namedtuple中的属性都是不可变的
可以验证创建的Point对象是tuple的子类
isinstance(p,Point) #True isinstance(p,tuple) #True
类似的,如果要用坐标和半径表示一个圆,也可以用namedtuple定义:
#namedtuple('名称',[属性list]) Circle = namedtuple('Circle',['x','y','r']) circle = Circle(x = '1', y = '2', r = '3') circle.x #1 circle.y #2 circle.r #3 #修改对象属性,注意用’_replace方法‘ c = circle._replace(r = '4') c #Circle(x='1', y='2', r='4') #将circle对象转换为字典,注意要使用’_asdict' circle._asdict
deque
使用list存储数据时,按索引访问元素很快,但是插入和删除就很慢,因为list是线性存储,数据量很大的时候,插入和删除效率会很低
deque是为了高效实现插入和删除操作的双向列表,它提供了两端都可以操作的队列,适合用于队列和栈
from collections import deque
from collections import deque q = deque(['a','b','c']) q.append('x') q.appendleft('y') q[0]
deque(['y', 'a', 'b', 'c', 'x'])
'y'
deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就可以非常高效的往头部添加或删除元素
from collections import deque q = deque(['a','b','c']) #与列表同样的操作 q.append('x') #右边加 q.appendleft('y')#左边加 q.insert(2,'z')#插入 q.count('x') #'x'出现几次 q.pop()#删除右边 q.popleft()#删除左边 q.index('b') q.extend(['e','f'])#右扩 q.extendleft(['1','2'])#左扩 q.reverse()#翻转 q.remove('1')#移除
defaultdict
使用dict时,如果引用的key不存在,就会抛出keyError,如果希望key不存在,返回一个默认值,就可以用defaultdict
dict1 = defaultdict(int) dict2 = defaultdict(set) dict3 = defaultdict(str) dict4 = defaultdict(list) #list对应[],str对应空字符串,set对应set(),int对应0 print(dict1[1]) print(dict2[1]) print(dict3[1]) print(dict4[1])
0 set() []
from collections import defaultdict dd = defaultdict(lambda:'N/A') dd['key1'] = 'abc' dd['key1'] #'abc' dd['key2']#key2不存在,返回默认值 #'N/A'
注意默认值是调用函数返回的,而函数在创建defaultdict对象时传入
除了在key不存在时返回默认值,defaultdict的其他行为跟dict是完全一样的
使用list作为第一个参数,可以很容易把键值对序列转换为字典
from collections import defaultdict s=[('yellow',1),('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)] d=defaultdict(list) for k, v in s: d[k].append(v) a=sorted(d.items()) print(a)
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
当字典中没有的键第一次出现时,default_factory自动为其返回一个空列表,list.append()会将值添加进空列表,再次遇到相同的键时,list.append()将其它值在添加进列表
defaultdict还可以被用来计数,将default_factory设为int即可
from collections import defaultdict s = 'mississippi' d = defaultdict(int) for k in s: d[k] += 1 print('\n',d) a = sorted(d.items()) print('\n',a)
defaultdict(<class 'int'>, {'m': 1, 'i': 4, 's': 4, 'p': 2}) [('i', 4), ('m', 1), ('p', 2), ('s', 4)]
字符串中的字母第一次出现时,字典中没有该字母,default_factory函数调用int()为其提供一个默认值0,加法操作将计算出每个字母出现的次数
default_factory设为set时,可以用defaultdict建立集合字典
from collections import defaultdict s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)] d = defaultdict(set) for k,v in s: d[k].add(v) print('\n',d) a = sorted(d.items()) print('\n',a)
defaultdict(<class 'set'>, {'red': {1, 3}, 'blue': {2, 4}}) [('blue', {2, 4}), ('red', {1, 3})]
OrderedDict
使用dict时,key是无序的,在对dict做迭代时,我们无法确定key的顺序
如果要保持key的顺序,可以用OrderedDict
from collections import OrderedDict d = dict([('a',1),('b',2),('c',3)]) d #{'a': 1, 'b': 2, 'c': 3},dict的key是无序的 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
chainmap
from collections import ChainMap a = {'x':1,'z':3} b = {'y':2,'z':4} c = ChainMap(a,b) print(c) print('x:{},y:{},z:{}'.format(c['x'],c['y'],c['z']))
ChainMap({'x': 1, 'z': 3}, {'y': 2, 'z': 4}) x:1,y:2,z:3
此为python的基本使用,可以用来合并两个或者更多个字典,当查询的时候,从前往后依次查询
ChainMap进行修改的时候总是只会对第一个字典进行修改
from collections import ChainMap a = {'x':1,'z':3} b = {'y':2,'z':4} c = ChainMap(a,b) #ChainMap({'z': 3, 'x': 1}, {'z': 4, 'y': 2}) c['z'] #3 c['z'] = 4 c #ChainMap({'x': 1, 'z': 4}, {'y': 2, 'z': 4}) c.pop('z') c #ChainMap({'x': 1}, {'y': 2, 'z': 4}) del c['y'] #"Key not found in the first mapping: 'y'"
ChainMap和带有作用域的值,诸如全局变量,局部变量之间工作的时候非常有效
a = ChainMap() a['x'] = 1 a #ChainMap({'x': 1}) b = a.new_child() #new_child()方法实质上是在列表的第一个元素前放入一个字典,默认是{},而parents时区掉了列表开头的元素 b #ChainMap({}, {'x': 1}) b['x'] #1 b['x'] = 2 b #ChainMap({'x': 2}, {'x': 1}) b['y'] = 3 b #ChainMap({'x': 2, 'y': 3}, {'x': 1}) d = b.parents #parents是去掉了列表开头的元素 d #ChainMap({'x': 1}) d is a #False d == a #True
从原理上来讲,ChainMap实际上是把放入的字典存储在一个队列中,当进行字典的增加删除等操作只会在第一个字典上进行,当进行查找的时候会一次查找,new_child()方法是实质上是在列表的第一个元素前放入一个字典,默认是{},而parents是去掉了列表开头的元素
from collections import ChainMap a = {'x':1,'z':3} b = {'y':2,'z':4} c = ChainMap(a,b) #ChainMap({'z': 3, 'x': 1}, {'z': 4, 'y': 2}) c.maps #[{'x': 1, 'z': 3}, {'y': 2, 'z': 4}] c.parents #ChainMap({'y': 2, 'z': 4}) c.parents.maps #[{'y': 2, 'z': 4}] c.parents.parents #ChainMap({}) c.parents.parents.parents #ChainMap({})
也正是因为底层是列表实现的,所以实际上ChainMap查询的字典实际上还是原来的字典的引用
Counter
counter是一个简单的计数器,例如,统计字符出现的个数
from collections import Counter c = Counter() for ch in 'programming': c[ch] = c[ch] + 1 c
Counter({'p': 1, 'r': 2, 'o': 1, 'g': 2, 'a': 1, 'm': 2, 'i': 1, 'n': 1})