一、集set
约定
set 翻译为集合
collection 翻译为集合类型或容器,是一个大概念
set
可变的、无序的、不重复的元素的集合
set定义 初始化
set() -> new empty set object
set(iterable) -> new set object
s1 = set()
s2 = set(range(5))
s3 = set(list(range(10)))
s4 = {} # ?错误写发,这样写是字典
s5 = {9,10,11} # set s6 = {(1,2),3,'a'}
s7 = {[1],(1,),1} # 不可以有非哈希值
1,元素
set的元素要求必须可以hash
目前学过的不可hash的类型有list、set、bytearray
元素不可以索引
set可以迭代
2,set增加
dd(elem)
增加一个元素到set中
如果元素存在,什么都不做
update(*others)
合并其他元素到set集合中来
参数others必须是可迭代对象
就地修改
3,set删除
remove(elem)
从set中移除一个元素元素不存在,抛出KeyError异常。为什么是KeyError?
discard(elem)
从set中移除一个元素
元素不存在,什么都不做
pop() -> item
移除并返回任意的元素。为什么是任意元素?
空集返回KeyError异常
clear()
移除所有元素
4,set修改、查询
修改
要么删除,要么加入新的元素
索引
非线性结构,无法索引
遍历
可以迭代所有元素
成员运算符
in 和 not in 判断元素是否在set中
5,set和线性结构
基本概念
全集
所有元素的集合。例如实数集,所有实数组成的集合就是全集
子集subset和超集superset
一个集合A所有元素都在另一个集合B内,A是B的子集,B是A的超集
真子集和真超集
A是B的子集,且A不等于B,A就是B的真子集,B是A的真超集
并集:多个集合合并的结果
union | 返回和多个集合合并后的新的集合
update |= 和多个集合合并,就地修改
交集:多个集合的公共部分
集合A和B,由所有属于A且属于B的元素组成的集合
intersection & 回和多个集合的交集
intersection_update &= 获取和多个集合的交集,并就地修改
差集:集合中除去和其他集合公共部分
集合A和B,由所有属于A 且不属于B的元素组成的集合
difference - 返回和多个集合的差集
difference_update -= 获取和多个集合的差集并就地修改
对称差集:
集合A和B,由所有不属于A和B的交集元素组成的集合,记作(A-B)∪(B-A)
symmetric_differece ^ 返回和另一个集合的对称差集
symmetric_differece_update ^= 获取和另一个集合的对称差集并就地修改
二、字典dict
key-value键值对的数据的集合
可变的、无序的、key不重复
字典dict定义 初始化
d = dict() #或者
d = {}
dict(**kwargs) # 使用name=value对初始化一个字典
dict(iterable, **kwarg) # 使用可迭代对象和name=value对构造字典,不过可迭代对象的元素必须是一个二元结构
d = dict(((1,'a'),(2,'b'))) # 或者
d = dict(([1,'a'],[2,'b']), c=300)
dict(mapping, **kwarg) # 使用一个字典构建另一个字典
d = {'a':10, 'b':20, 'c':None, 'd':[1,2,3]}
# 类方法dict.fromkeys(iterable, value)
d = dict.fromkeys(range(5))
d = dict.fromkeys(range(5),0)
字典元素的访问
d[key]
返回key对应的值value
ey不存在抛出KeyError异常
get(key[, default])
返回key对应的值value
key不存在返回缺省值,如果没有设置缺省值就返回None
setdefault(key[, default])
返回key对应的值value
key不存在,添加kv对,value设置为default,并返回default,如果default没有设置,缺省为None
如果KV对已经有值,即使给你输入Value值,返回也是原本的 Value值
字典增加和修改
d[key] = value
将key对应的值修改为value
key不存在添加新的kv对
update([other]) -> None
使用另一个字典的kv对更新本字典
key不存在,就添加
key存在,覆盖已经存在的key对应的值
就地修改
d = {}
d.update(red=1) # {'red': 1}
d.update((('red',2),)) # {'red': 2}
d.update({'red':3}) # {'red': 3}
字典删除
pop(key[, default])
key存在,移除它,并返回它的value
key不存在,返回给定的default
default未设置,key不存在则抛出KeyError异常
popitem()
移除并返回一个任意的键值对
字典为empty,抛出KeyError异常
clear()
清空字典
del语句
a = True
b = [1]
d = {'a':1, 'b':b, 'c':[1,3,5]}
del a # 删除了a
del b[0] # 删除了b列表的第一个元素
del d['c'] # 删除了key值的velue值[1,3,5]
del c # NameError
del b # 删除了列表b
del d['b'] # 删除了字典d中key ‘b'的velue值 b
字典遍历
for … in dict
遍历key
遍历value
遍历item,即kv对
d = {'a':1, 'b':B, 'c':[1,3,5]}
for b in d: # a B c
print(b)
for b in d.keys():
print(b) # a B c
for b in d.values():
print(b) # 1 B [1,3,5]
for b in d:
print(b[b]) # 1 B [1,3,5]
for b in d.keys():
print(b.get(b)) # 1 B [1,3,5]
for b,_ in d.items():
print(b) # B
for _ ,b in d.items():
print(b) # b
总结
Python3中,keys、values、items方法返回一个类似一个生成器的可迭代对象,不会把函数的返回结果复制到内存中
Dictionary view对象,可以使用len()、iter()、in操作
字典的entry的动态的视图,字典变化,视图将反映出这些变化
keys返回一个类set对象,也就是可以看做一个set集合。如果values都可以hash,那么items也可以看做是类set对象
Python2中,上面的方法会返回一个新的列表,占据新的内存空间。所以Python2建议使用iterkeys、 itervalues、iteritems版本,返回一个迭代器,而不是返回一个copy
字典遍历和移除
d = dict(a=1, b=2, c='abc')
keys = []
for k,v in d.items():
if isinstance(v, str):
keys.append(k)
for k in keys:
d.pop(k)
print(d)
# {'a': 1, 'b': 2}
字典的key
key的要求和set的元素要求一致
set的元素可以就是看做key,set可以看做dict的简化版
hashable 可哈希才可以作为key,可以使用hash()测试
d = {1 : 0, 2.0 : 3, “abc” : None, (‘hello’, ‘world’, ‘python’) : “string”, b’abc’ : ‘135’}
defaultdict
collections.defaultdict([default_factory[, …]])
第一个参数是default_factory,缺省是None,它提供一个初始化函数。当key不存在的时候,会调用这个工厂函数来生成key对应的value
from collections import defaultdict import random
d1 = defaultdict(list)
for k in 'abcdef':
for i in range(random.randint(1,5)):
d1[k].append(i)
print(d1)
# defaultdict(<class 'list'>, {'a': [0, 1, 2, 3], 'b': [0, 1], 'c': [0, 1, 2, 3], 'd': [0, 1, 2, 3], 'e': [0, 1, 2], 'f': [0, 1, 2]})
OrderedDict
collections.OrderedDict([items])
key并不是按照加入的顺序排列,可以使用OrderedDict记录顺序
from collections import OrderedDict
import random
d = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}
print(d)
keys = list(d.keys())
random.shuffle(keys)
print(keys)
od = OrderedDict()
for key in keys:
od[key] = d[key]
print(od)
print(od.keys())
# {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}
# ['orange', 'pear', 'apple', 'banana']
# OrderedDict([('orange', 2), ('pear', 1), ('apple', 4), ('banana', 3)])
# odict_keys(['orange', 'pear', 'apple', 'banana'])
有序字典可以记录元素插入的顺序,打印的时候也是按照这个顺序输出打印
3.6版本的Python的字典就是记录key插入的顺序(IPython不一定有效果)
应用场景:
假如使用字典记录了N个产品,这些产品使用ID由小到大加入到字典中
除了使用字典检索的遍历,有时候需要取出ID,但是希望是按照输入的顺序,因为输入顺序是有序的
否则还需要重新把遍历到的值排序
三、解析式、生成器
标准库datetime
对日期、时间、时间戳的处理
datetime类
类方法
today() 返回本地时区当前时间的datetime对象
now(tz=None) 返回当前时间的datetime对象,时间到微秒,如果tz为None,返回和today()一样
utcnow() 没有时区的当前时间
fromtimestamp(timestamp, tz=None) 从一个时间戳返回一个datetime对象
datetime对象
timestamp() 返回一个到微秒的时间戳。
时间戳:格林威治时间1970年1月1日0点到现在的秒数
构造方法 datetime.datetime(2016, 12, 6, 16, 29, 43, 79043)
year、month、day、hour、minute、second、microsecond,取datetime对象的年月日时分秒及微秒
weekday() 返回星期的天,周一0,周日6
isoweekday() 返回星期的天,周一1,周日7
date() 返回日期date对象
time() 返回时间time对象
replace() 修改并返回新的时间
isocalendar() 返回一个三元组(年,周数,周的天)
日期格式化*
类方法 strptime(date_string, format) ,返回datetime对象
对象方法 strftime(format) ,返回字符串
字符串format函数格式化
import datetime
dt = datetime.datetime.strptime("21/11/06 16:30", "%d/%m/%y %H:%M") print(dt.strftime("%Y-%m-%d %H:%M:%S"))
print("{0:%Y}/{0:%m}/{0:%d} {0:%H}::{0:%M}::{0:%S}".format(dt))
# 2006-11-21 16:30:00
# 2006/11/21 16::30::00
timedelta对象
datetime2 = datetime1 + timedelta
datetime2 = datetime1 - timedelta
timedelta = datetime1 - datetime2
构造方法
datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)
year = datetime.timedelta(days=365)
total_seconds() 返回时间差的总秒数
标准库time
time
time.sleep(secs) 将调用线程挂起指定的秒数
列表解析List Comprehension
语法
[返回值 for 元素 in 可迭代对象 if 条件]
使用中括号[],内部是for循环,if条件语句可选
返回一个新的列表
列表解析式是一种语法糖
编译器会优化,不会因为简写而影响效率,反而因优化提高了效率
减少程序员工作量,减少出错
简化了代码,但可读性增强
even = []
for x in range(10):
if x % 2 == 0:
even.append(x)
even = [x for x in range(10) if x%2==0]
[expr for item in iterable if cond1 if cond2]
ret = []
for item in iterable:
if cond1:
if cond2:
ret.append(expr)
[expr for i in iterable1 for j in iterable2 ]
ret = []
for i in iterable1:
for j in iterable2:
ret.append(expr)
生成器表达式Generator expression
语法
(返回值 for 元素 in 可迭代对象 if 条件)
列表解析式的中括号换成小括号就行了
返回一个生成器
和列表解析式的区别
生成器表达式是按需计算(或称惰性求值、延迟计算),需要的时候才计算值
列表解析式是立即返回值
生成器
可迭代对象
迭代器
g = ("{:04}".format(i) for i in range(1,11))
next(g)
for x in g:
print(x)
for x in g:
print(x)
# 延迟计算
# 返回迭代器,可以迭代
# 从头走到完,不能回头,除非生成新的
g = ["{:04}".format(i) for i in range(1,11)]
for x in g:
print(x)
for x in g:
print(x)
# 立即计算
# 返回的不是迭代器,返回可迭代对象列表
# 从前到后早完一遍后,可以重新回头迭代
和列表解析式的对比
计算方式
生成器表达式延迟计算,列表解析式立即计算
内存占用
但从返回值本身来说,生成器表达式省内存,列表解析式返回新的列表
生成器没有数据,内存占用极少,但是使用的时候,虽然一个个返回数据,但是合起来占用的内存也差不多
列表解析式构造新的列表需要占用内存
计算速度
单看计算时间看,生成器表达式耗时非常短,列表解析式耗时长
但是生成器本身并没有返回任何值,只返回了一个生成器对象
列表解析式构造并返回了一个新的列表
集合解析式
语法
{返回值 for 元素 in 可迭代对象 if 条件}
列表解析式的中括号换成大括号{}就行了
立即返回一个集合
用法
{(x,x+1) for x in range(10)}
{[x] for x in range(10)} #
字典解析式
语法
{返回值 for 元素 in 可迭代对象 if 条件}
列表解析式的中括号换成大括号{}就行了
使用key:value形式
立即返回一个字典
用法
{x:(x,x+1) for x in range(10)}
# {0: (0, 1),
# 1: (1, 2),
# 2: (2, 3),
# 3: (3, 4),
# 4: (4, 5),
# 5: (5, 6),
# 6: (6, 7),
# 7: (7, 8),
# 8: (8, 9),
# 9: (9, 10)}
{x:[x,x+1] for x in range(10)}
# {0: [0, 1],
# 1: [1, 2],
# 2: [2, 3],
# 3: [3, 4],
# 4: [4, 5],
# 5: [5, 6],
# 6: [6, 7],
# 7: [7, 8],
# 8: [8, 9],
# 9: [9, 10]}
{(x,):[x,x+1] for x in range(10)}
#{(0,): [0, 1],
# (1,): [1, 2],
# (2,): [2, 3],
# (3,): [3, 4],
# (4,): [4, 5],
# (5,): [5, 6],
# (6,): [6, 7],
# (7,): [7, 8],
# (8,): [8, 9],
# (9,): [9, 10]}
{[x]:[x,x+1] for x in range(10)}
# TypeError
{chr(0x41+x):x**2 for x in range(10)}
#{'A': 0,
# 'B': 1,
# 'C': 4,
# 'D': 9,
# 'E': 16,
# 'F': 25,
# 'G': 36,
# 'H': 49,
# 'I': 64,
# 'J': 81}
{str(x):y for x in range(3) for y in range(4)}
# {'0': 3, '1': 3, '2': 3}
用法
{str(x):y for x in range(3) for y in range(4)}
# {'0': 3, '1': 3, '2': 3}
ret = {}
for x in range(3):
for y in range(4):
ret[str(x)] = y
总结
Python2 引入列表解析式
Python2.4 引入生成器表达式
Python3 引入集合、字典解析式,并迁移到了2.7
一般来说,应该多应用解析式,简短、高效
如果一个解析式非常复杂,难以读懂,要考虑拆解成for循环
生成器和迭代器是不同的对象,但都是可迭代对象
三、内建函数
标识 id
返回对象的唯一标识,CPython返回内存地址
哈希 hash()
返回一个对象的哈希值
类型 type()
返回对象的类型
类型转换
float() int() bin() hex() oct() bool() list() tuple() dict() set() complex() bytes() bytearray()
输入 input([prompt])
接收用户输入,返回一个字符串
打印 print(*objects, sep=’ ‘, end=’\n’, file=sys.stdout, flush=False)
打印输出,默认使用空格分割、换行结尾,输出到控制台
对象长度 len(s)
返回一个集合类型的元素个数
isinstance(obj, class_or_tuple)
判断对象obj是否属于某种类型或者元组中列出的某个类型
isinstance(True, int)
issubclass(cls, class_or_tuple)
判断类型cls是否是某种类型的子类或元组中列出的某个类型的子类
issubclass(bool, int)
绝对值abs(x) x为数值
最大值max() 最小值min()
返回可迭代对象中最大或最小值
返回多个参数中最大或最小值
round(x) 四舍六入五取偶,round(-0.5)
pow(x , y) 等价于 x**y
range(stop) 从0开始到stop-1的可迭代对象;range(start, stop[, step])从start开始到stop-1结束步长为step的可迭代对象
divmod(x, y) 等价于 tuple (x//y, x%y)
sum(iterable[, start]) 对可迭代对象的所有数值元素求和
sum(range(1,100,2))
chr(i) 给一个一定范围的整数返回对应的字符
chr(97) chr(20013)
ord(c) 返回字符对应的整数
ord('a') ord('中')
sorted(iterable[, key][, reverse]) 排序
返回一个新的列表,默认升序
reverse是反转
sorted([1, 3, 5])
# [1, 3, 5]
sorted([1, 3, 5], reverse=True)
# [5, 3, 1]
sorted({'c':1, 'b':2, 'a':1})
# ['a', 'b', 'c']
翻转 reversed(seq)
返回一个翻转元素的迭代器
for x in reversed(['c','b','a']):
print(x)
# a b c
枚举 enumerate(seq, start=0)
迭代一个序列,返回索引数字和元素构成的二元组
start表示索引开始的数字,默认是0
for x in enumerate([2,4,6,8]):
print(x)
for x in enumerate("abcde"):
print(x,end=" ")
# (0, 2)
#(1, 4)
# (2, 6)
# (3, 8)
# (0, 'a') (1, 'b') (2, 'c') (3, 'd') (4, 'e')
迭代器和取元素 iter(iterable)、next(iterator[, default])
iter将一个可迭代对象封装成一个迭代器
next对一个迭代器取下一个元素。如果全部元素都取过了,再次next会抛StopIteration异常
it = iter(range(5))
next(it)
# 0
it = reversed([1,3,5])
next(it)
# 5
可迭代对象
能够通过迭代一次次返回不同的元素的对象。
所谓相同,不是指值是否相同,而是元素在容器中是否是同一个,例如列表中值可以重复的,[‘a’, ‘a’],虽然这个列表有2个元素,值一样,但是两个’a’是不同的元素
可以迭代,但是未必有序,未必可索引
可迭代对象有:list、tuple、string、bytes、bytearray、range、set、dict、生成器等
可以使用成员操作符in、not in,in本质上对于线性数据结构就是在遍历对象
3 in range(10)
# True
3 in (x for x in range(10))
# True
3 in {x:y for x,y in zip(range(4),range(4,10))}
# True
迭代器
特殊的对象,一定是可迭代对象,具备可迭代对象的特征
通过iter方法把一个可迭代对象封装成迭代器
通过next方法,迭代 迭代器对象
生成器对象,就是迭代器对象
for x in iter(range(10)):
print(x)
g = (x for x in range(10))
print(type(g))
print(next(g))
print(next(g))
# 0 1 2 3 4 5 6 7 8 9
# <class 'generator'>
# 0
# 1
拉链函数zip(*iterables)
像拉链一样,把多个可迭代对象合并在一起,返回一个迭代器
将每次从不同对象中取到的元素合并成一个元组
list(zip(range(10),range(10)))
# [(0, 0),(1, 1),(2, 2),(3, 3),(4, 4)l, (5, 5),(6, 6),(7, 7),(8, 8),(9, 9)]
list(zip(range(10),range(10),range(5),range(10)))
# [(0, 0, 0, 0), (1, 1, 1, 1), (2, 2, 2, 2), (3, 3, 3, 3), (4, 4, 4, 4)]
dict(zip(range(10),range(10)))
# {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}
{str(x):y for x,y in zip(range(10),range(10))}
# {'0': 0,'1': 1,'2': 2,'3': 3, '4': 4,'5': 5,'6': 6,'7': 7,'8': 8,'9': 9}