【JulyEdu-Python基础】第 3 课:容器以及容器的访问使用

时间:2021-09-08 18:42:03

大纲

  • 容器切片
    • list/tuple
      dict
      set

  • 切片
  • 列表推导
  • 生成器
  • 迭代器 

容器

list 列表

  序列是Python中最基本的数据结构。序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推。
  列表的数据项不需要具有相同的类型

 tuple 元组(只读列表)

  像C++的const

dict 字典

字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中。

set 集合  

  是一个无序不重复元素集, 基本功能包括关系测试和消除重复元素. 集合对象还支持union(联合), intersection(交), difference(差)和sysmmetric difference(对称差集)等数学运算。

 容器 - list/tuple基本操作

li = [1, 2, 3, '456', [1, 2, 3], {1: 'one', 2: 'two'}]
print(type(list))      
print(type(li))

<class 'type'>
<class 'list'>

# 元素访问
print(li[0])
print(li[-1])    # li[len(li) - 1]
print(li[-2])    # li[len(li) - 2]

 

# 查找元素位置
print(li.index('456'))
print(li.index([1, 2, 3]))
#print(li.index(-1))

创建
添加元素(list only):append, extend

# 添加元素
l_a= [1, 2, 3]
l_a.append(4)
l_a.append(5)
l_b = [6, 7, 8]
l_a.extend(l_b) # 试用下append什么结果
print(l_a)

def my_extend(li, n_li):
    for i in n_li:
        li.append(li)
# 其实就是把要添加的数组展开了

 

删除元素(list only):del, pop


根据索引读写(tuple只读)


判断容器是否为空

# 判断容器是否为空
l_a = []
if not l_a:
    print('Empty')
if l_a is None:
    print('Empty')# 没有分配内存,不显示
# None和not 不是一回事
if len(l_a) == 0:
    print('Empty')

 

字符串转换
容器元素数量
遍历

# 遍历
for i in li:
    print(i)# 直接遍历
for i in range(len(li)):
    print(li[i])# 根据索引去访问每个元素

 

容器 - dict基本操作

初始化
访问
添加元素
修改元素
删除元素
判断key是否存在
判断容器是否为空
容器元素数量
遍历

# 无序的key:value数据结构

d = {'a': 1, 'b': 2, 1: 'one', 2: 'two', 3:[1, 2, 3]}

print(type(dict))
print(type(d))
print(d)

# 访问元素
print(d['a'])
print(d[1])
print(d[3])

# 判断元素是否存在
print('c' in d)
print(3 in d)

del(d['a'])# del(dict[key])

print(len(d))

 

#遍历
d = {'a': 1, 'b': 2, 1: 'one', 2: 'two', 3:[1, 2, 3]}
for key in d:
    print(d[key])
print('.....')
for key, value in d.items():
    print(key, value)

keys = d.keys()
print(type(keys))
print(keys)

容器 - set基本操作

并/交/差集:|/union, &/intersection, -/difference
对称差集:^/symmetric_difference(不同时出现在2个集合中的项)
包含关系:>=/issuperset
添加元素
更新元素
删除元素
元素是否存在
容器元素数量
遍历

print(s_a.difference(s_b))

# 对称差(A | B) - (A & B)
print(s_a ^ s_b)
print(s_a.symmetric_difference(s_b))

# 修改元素
s_a.add('x')
s_a.update([4, 5, 60, 70])
print(s_a)

# 删除元素 必须知道元素的值
s_a.remove(70)
print(s_a)
# s_a.remove(100)

# 遍历
print(len(s_a))
for i in s_a:
    print(i)

 

切片

存取序列(列表,元组,字符串)的任意一部分

格式:seq[开始索引:结束索引:步长]

  默认值
  负数索引
  负数步长

# python的大杀器,怎么高效的切一个子数组,切片最大的用处
li = list(range(10))
print(li)

# 切片 [start:end:steps] >= start & < end开区间 
print(li[2:5])    # [2,3,4]
print(li[:4])     # [0,1,2,3]
print(li[5:])     # [5,6,7,8,9]
print(li[0:10:3]) # [0,3,6,9]

# 负数怎么处理?
print(li[5:-2])   # [5,6,7]
print(li[9:0:-1]) # [9,8,7,6,5,4,3,2,1]
print(li[9::-1])  # [9,8,7,6,5,4,3,2,1,0]
print(li[::-2])   # [9,7,5,3,1]

#切片生成一个新的对象
print(li)         # 还是保持原样

# 切片做快速反转
re_li = li[::-1]
print(re_li)

 

列表推导

问题的提出

  •   快速简单的生成一个列表

  •   对原有的列表进行简单的转换

一维列表推导
二维列表推导以及注意事项

 

#生成数组对象的方法
li = list(range(10))
print(li)

li = []
for i in range(20):
    if(i % 2) == 0:
        li.append(i)

print(li)

li = [0] * 10 
print(li)

# 列表推导
li = [i * 2 for i in range(10)]
print(li)

# 浅拷贝
li_2d = [[0] * 3] * 3# ×3代表把[[0]*3]引用了3次,每一列都是同一个对象
print(li_2d)
li_2d[0][0] = 100 # 同时对这个3个都起了效果
print(li_2d)    # [[100,0,0],[100,0,0],[100,0,0]]

# 深拷贝
li_2d = [[0] * 3 for i in range(3)]
li_2d[0][0] = 100 # 同时对这个3个都起了效果
print(li_2d)    # [[100,0,0],[100,0,0],[100,0,0]]
# 1维情况下做复制操作,多维使用的是引用

# python3字典和集合也支持列表推导操作,python2不支持
set = { x for x in range(10) if x % 2 == 0}
print(set)

dict = {x: x % 2 == 0 for x in range(10)}
print(dict)

 

生成器

问题的提出

  • 创建一个巨大的列表而仅仅需要访问其中少量几个元素
  • 如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。

生成生成器:列表推导时用()替换[](关于yield的使用后面再讲)

遍历:next或者for循环

 

# 平方表
square_table = []
for i in range(10000):
    square_table.append(i * i)

for i in range(10):
    print(square_table[i])

# 生成器,没有任何初始化开销的时间,把真正的计算推迟到你使用的时候
square_generator = (x * x for x in range(50000))
print(type(square_generator))
for i in range(10):
    print(next(square_generator))

# 在python3里range它返回一个新的对象,不是一个list,
# 是一个<class 'range'>,定义了一个生成器
print(type(range(10)))

# 协程,可控多线程
def fib(limit):
    n, a, b = 0, 0, 1
    while n < limit:
        yield b
        a, b = b, a + b
        n += 1
    return 'done'

import traceback
f = fib(5)
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
try:
    print(next(f))
except StopIteration:
    traceback.print_exc()

for i in fib(5):
    print(i)

 

迭代器

问题的提出

  • 可以直接作用于for循环的对象统称为可迭代对象:Iterable
  • 可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator(表示一个惰性计算的序列)

集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

from collections import Iterable
from collections import Iterator

print(isinstance([1, 2, 3], Iterable))# 数组是可迭代的
print(isinstance([1, 2, 3], Iterator))# 但不是一个迭代器

print(isinstance({}, Iterable))       # True
print(isinstance({}, Iterator))       # False

print(isinstance(123, Iterable))      # False

print(isinstance('abc', Iterable))    # True
print(isinstance('abc', Iterator))    # False

g = (x * x for x in range(3))
print(type(g))
print(isinstance(g, Iterable))        # True
print(isinstance(g, Iterator))        # True
for i in g:
    print(i)

def fib(limit):
    n, a, b = 0, 0,1 
    while n < limit:
        yield b 
        a, b = b, a+b
        n += 1
    return 'done'
f = fib(6)
print(type(f))
print(isinstance(f, Iterable))        # True
print(isinstance(f, Iterator))        # True
for i in f:  
    print(i)