一、元组和列表
1.元祖和列表的性能分析
- 测试环境:ipython 中使用 timeit模块
- 计算时间模块介绍:
# ipython环境下
In [1]: timeit list1=[1,2,3]
42.3 ns ± 1.2 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [2]: timeit tuple1=(1,2,3)
12.3 ns ± 0.0096 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
# 总结:可以看到初始化列表一千万次是初始化一千万次元组时间的三倍多,所以在数据确认的情况下尽可能使用元组储存数据
import timeit # python下用来性能分析
def func():
for i in range(10):
print(i)
# 函数等需要传函数名
times = timeit.timeit(func, number=5)
print(times)
# 数据类型需要传字符串,number默认值一千万次
times=timeit.timeit("[1,2,3]")
print(times)
2.命名元组
正常元组的取值方式是通过下标,不够人性化,命名元组就实现可以像字典那样取值
- 方式一(没事找事)
# 方式一 ,先把先把下标赋值给key,然后就可以通过key取值了 太low
tu=["小明",18,"男"]
name=0
age=1
gender=2
print(tu[name])
print(tu[age])
print(tu[gender])
- 方式二 :collections 模块里的 namedtuple方法
from collections import namedtuple
# typename:类型名字 ,field_names:这个元组元素的名称,传一个列表
info_tuple = namedtuple(typename="info_tuole", field_names=["name", "age", "gender"])
# 单个元组
tu = info_tuple("小明", 18, "男")
print(tu)
print(tu.age)
二、字典和集合的原理和应用
dict和set实现原理是一样的都是无序的,都是将实际的值放到list中,唯一不通的在于hash函数操作对象不同,对于dict,hash函数操作的是其key,而set是直接操作的它的元素,假设操作元素为“X”,其作为变量,放入hash函数,通过运算后取list的余数,作为list的下标存储起来,set就直接存放set本身元素,叫做hash set,而对于dict则是创建两个list,一个list存key,一个list存value,叫做hash map(map就是通过key找value的过程)
- 定义集合set
- 最大作用自动去重
- 关系性测试数据:交集,并集,差集,对称差集
# 定于空集合
se = set()
se.add(1) # 单个添加
se.update([1, 2, 3, 4, 2, 2]) # 添加多个
se.remove(1)
print(se)
a=set([1,2,3,4,5,6])
b=set([4,5,7,8,9])
# 交集intersection
print(a.intersection(b)) #>>>{5, 6}
# 并集union
print(a.union(b)) # >>>{1, 2, 3, 4, 5, 6, 7, 8, 9}
# 差集:在a中不在b中的
print(a.difference(b)) # >>>{1, 2, 3, 4}
# 对称差集:反向交集
print(a.symmetric_difference(b)) # >>>{1, 2, 3, 4, 7, 8, 9}
# 超集:判断a是不是完全包含b a>=b
print(a.issuperset(b))
# 子集:判断a是不是b的子集 a<=b
print(a.issubset(b))
- 字典
- 性能分析
- 从时间上(快-慢):集合、字典、元组、列表
- 从内存上(少-多):元组、列表、集合、字典
三、推导式
- 列表推导式
# 如生成0-100的单数的平方列表
list1 = [i*i for i in range(1, 101) if i % 2 == 1]
print(list1)
- 字典推导式
cook_str = 'BIDUPSID=D0727533D7147B7;PSTM=1530348042;BAIDUID=B1005C9BC2EB28;sugstore=0'
dict_str = {i.split("=")[0]: i.split("=")[1] for i in cook_str.split(";")}
四、生成器
- 生成器表达式
# 生成器表达式 内部实现了生成器协议-有__next__方法
gen = (i for i in range(20))
print(gen)
print(dir(gen))
# 通过next()方法生成一个取一个,取玩在取报错StopIteration
print(next(gen))
print(next(gen))
print(next(gen))
# 可以通过for 循环取值
for i in gen:
print(i)
- 函数生成器
- send方法
- close方法
- throw方法
def gen_fun():
for i in range(1,10):
send_value = yield i
print(send_value)
# 赋值生成器对象
res = gen_fun()
print(res)
# 执行到yield 返回1
print(next(res))
# 继续执行 给send_value赋值 因为不没有传 所以是None 执行打印None 在继续执行循环到yield,返回2
print(next(res))
# 继续执行 给send_value赋值 send的值100 打印100 执行打印100 在继续执行循环到yield,返回3
# send方法在去过一次值后,程序执行到yield后菜能使用
print(res.send(100))
#继续执行 给send_value赋值 因为不没有传 所以是None 执行打印None 在继续执行循环到yield,返回2
print(next(res))
res_1=gen_fun()
print(next(res_1))
res_1.close() # close 方法关闭生成器
print(next(res_1)) # >>>StopIteration 报错
res_2=gen_fun()
# 让生成器抛错机制 第一个参数:异常类型 ;第二个参数:异常信息
res_2.throw(ValueError,"value异常") # >>>ValueError: value异常
五、迭代器
- 可迭代对象是序列不是迭代器,可被for循环遍历取值,内部有__iter__()方法,没有__next__()方法
- 可迭代对象可以通过iter方法实现可迭代协议,将可迭代对象转换成迭代器,内部有__next__()
- 生成器是一种特殊的迭代器
- 生成器相对迭代器多了几种方法(__del__,__qualname__,'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw')
list_1=[1,2,3,4,5]
iterator=iter(list_1)
print(iterator)
print(next(iterator))
print(next(iterator))