数据类型----列表的内置方法
一、定义
'''
中括号括起来,内部有多种元素,元素与元素之间用逗号隔开,元素可以是任意数据类型和嵌套
'''
# 定义
l1 = [1,'a',[1,2]] # 本质:l1 = list([1,'a',[1,2]])
二、类型转换
但凡能被for循环遍历的数据类型都可以传给list()转换成列表类型,除了整型和浮点型
# print(list(123)) 不可
# print(list(1.11)) 不可
# list()会跟for循环一样遍历出数据类型中包含的每一个元素然后放到列表中
print(list('hello')) # ['h', 'e', 'l', 'l', 'o']
print(list([11, 22, 33, 44])) # [11, 22, 33, 44]
print((list({'username': "kevin", "age": 20}))) # ['username', 'age']
print(list((11, 22, 33, 44))) # [11, 22, 33, 44]
print(list({11, 22, 33, 44})) # [33, 11, 44, 22]

三、使用
3.1 优先掌握的操作
3.1.1 按索引取值
# 1.按索引存取值(正向存取+反向存取):即可存也可以取
# 1.1 正向取(从左往右)
my_friends = ['tony', 'jason', 'tom', 4, 5]
print(my_friends[0]) # tony
print(my_friends[3]) # 4
# 1.2 反向取(负号表示从右往左)
print(my_friends[-1]) # 5
print(my_friends[-3]) # tom
print(my_friends[-5]) # tony
# 1.3 对于list来说,既可以按照索引取值,又可以按照索引修改指定位置的值,但如果索引不存在则报错
my_friends[1] = 'martthow'
print(my_friends) # ['tony', 'martthow', 'tom', 4, 5]
3.1.2 []切片
# 2.切片(顾头不顾尾,步长)
# 2.1 顾头不顾尾:取出索引为0到3的元素
print(my_friends[0:4]) # ['tony', 'jason', 'tom', 4]
# 2.2 步长:0:4:2,第三个参数2代表步长,会从0开始,每次累加一个2即可,所以会取出索引0、2的元素
print(my_friends[0:4:2]) # ['tony', 'tom']
3.1.3 长度len
# 3.长度len -> length
print(len(my_friends)) # 5
3.1.4 成员运算 in 和 not in
# 4.成员运算in和not in
# 成员运算是判断元素是否在列表中
print('tony' in my_friends) # True
print('t' in my_friends) # False
print('xx' in my_friends) # False
3.2 增删改查

3.2.1 增加
append:默认追加到末尾(不管是什么类型的数据,都会当成一个整体元素填进去)
insert:在指定位置添加元素(索引位置,不管是什么类型的数据,都会当成一个整体元素填进去)
extend:合并两个列表,把第二个列表的元素加到末尾
# 1.增加
my_friends = ['tony', 'jason', 'tom', 4, 5]
# 1.1 append()列表尾部追加元素
# 不能使用索引增加,会报错
# my_friends[5] = 666
my_friends.append(666)
# print(my_friends) # ['tony', 'jason', 'tom', 4, 5, 666]
my_friends.append(777)
print(my_friends) # ['tony', 'jason', 'tom', 4, 5, 666, 777]
# 1.2 insert:增加指定索引位置的值
my_friends.insert(0, 999)
print(my_friends) # [999, 'tony', 'jason', 'tom', 4, 5]
my_friends.insert(2, 'kevin')
print(my_friends) # [999, 'tony', 'kevin', 'jason', 'tom', 4, 5]
# 1.3 extend:合并两个列表
# append是把列表的整体添加到末尾
my_friends.append([11, 22, 33, 44])
print(my_friends) # ['tony', 'jason', 'tom', 4, 5, [11, 22, 33, 44]]
# 想要将第二个列表中的元素加到第一个列表中只能用,extend
my_friends.extend([11, 22, 33, 44])
print(my_friends) # ['tony', 'jason', 'tom', 4, 5, 11, 22, 33, 44]
l = ['kevin', 'jack', 'tom']
l1 = ['a', 'b', 'c', 'd']
l.extend(l1) # for循环+append
print(l)
# extend中只有一个参数,所以想要加第三个列表,只能是一个一个列表添加,不能一次性加两个,会报错
l = ['kevin', 'jack']
l1 = ['a', 'b']
l2 = [11, 22, 33, 44]
l.extend(l1)
print(l) # ['kevin', 'jack', 'a', 'b']
l.extend(l2)
print(l) # ['kevin', 'jack', 'a', 'b', 11, 22, 33, 44]
3.2.2 删除
del l[0]:删除指定索引的值
remove():删除指定的元素,可不是索引
pop():弹出元素 (1. 把列表的元素删除 2. 把删除的元素又返回过来了)
# 2.删除
my_friends = ['tony', 'jason', 'tom', 4, 5]
# 2.1 del -> delete: 删除指定索引的值
# del 变量[索引]
del my_friends[0]
print(my_friends) # ['jason', 'tom', 4, 5]
del my_friends[2]
print(my_friends) # ['jason', 'tom', 5]
# 2.2 remove()
# 括号中直接写删除的元素,可不是索引,没有返回值
aa = my_friends.remove('jason')
print(aa) # None 空
print(my_friends) # ['tony', 'tom', 4, 5]
# 从左往右查找第一个需要删除的元素
l = [11, 22, 33, 22, 44]
l.remove(22)
print(l) # [11, 33, 22, 44]
# 2.3 pop():弹出元素
# 默认删除列表最后一个元素,并将删除的值返回,括号内可以通过加索引值来指定删除元素
my_friends.pop()
print(my_friends) # ['tony', 'jason', 'tom', 4]
aa = my_friends.pop()
print(aa) # 4
print(my_friends) # ['tony', 'jason', 'tom']
# 可以弹出指定索引的值
s = my_friends.pop(1)
print(s) # jason
print(my_friends) # ['tony', 'tom']
# 如果删除空列表,会报错
# pop() 方法的默认行为是移除并返回列表的最后一个元素(即索引为 -1 的元素)。空列表里没有任何元素,自然也就没有“最后一个元素”可以返回,因此 Python 会抛出索引越界错误。
3.2.3 修改
# 3.修改
'''列表的最大索引长度:len(l)-1'''
print(my_friends[1]) # jason
# 1. 修改值:用索引来修改
my_friends[1] = 'jack'
print(my_friends) # ['tony', 'jack', 'tom', 4, 5]
3.2.4 查找
# 查找:用索引取值
print(my_friends[0]) # tony
print(my_friends[-1]) # 5
3.3 需要了解的操作

3.3.1 reverse()
# 1.reverse()颠倒列表内元素顺序
l1 = [11, 22, 33, 44]
# l1.reverse()
# print(l1) # [44, 33, 22, 11]
# 颠倒列表还可以使用:切片方式
print(l1[::-1]) # [44, 33, 22, 11]
3.3.2 sort()
# 2.sort()给列表内所有元素排序
l2 = [11, 22, 3, 42, 7, 55]
# 2.1 排序时列表元素之间必须是相同数据类型,不可混搭,否则报错
# 默认从小到大排序
l2.sort()
print(l2) # [3, 7, 11, 22, 42, 55]
# reverse用来指定是否跌倒排序,默认为False。reverse=True表示从大到小排序
l2.sort(reverse=True)
print(l2) # [55, 42, 22, 11, 7, 3]
# 2.2 了解知识
# 我们常用的数字类型直接比较大小,但其实,字符串、列表等都可以比较大小
# 原理相同:都是依次比较索引对应位置的元素的大小,如果分出大小,则无需比较下一个元素,比如
l1 = [666, 777]
l2 = [111, 222, 333, 444, 555, 666]
print(l2 > l1) # False
# 字符之间的大小取决于它们在ASCII表中的先后顺序,越往后越大
s1 = 'abc'
s2 = 'az'
print(s2 > s1) # True
# s1与s2的第一个字符没有分出胜负,但第二个字符'z'>'b',所以s2>s1成立
# 所以我们也可以对下面这个列表排序
l3 = ['A', 'z', 'adjk', 'hello', 'hea']
l3.sort()
print(l3) # ['A', 'adjk', 'hea', 'hello', 'z']
3.3.3 循环
# 循环遍历my_friends列表里面的值
my_friends=['tony','jason','tom',4,5]
for line in my_friends:
print(line)
面试题
把一个列表反转的方法
- 直接改原列表 ➡️ 用 my_list.reverse()
- 要生成新列表 ➡️ 用 my_list[::-1]
- 仅仅为了遍历 ➡️ 用 reversed(my_list)
# 方法 1:使用 reverse() 方法(原地反转,最常用)
# 如果你不需要保留原来的列表,直接在原列表上进行反转,这是最省内存的方法。
# 注意:reverse() 方法没有返回值(返回 None),它是直接修改原列表。
my_list = [1, 2, 3, 4, 5]
my_list.reverse()
print(my_list) # [5, 4, 3, 2, 1]
# 方法 2:使用切片 [::-1](生成新列表,非常优雅)
# 如果你需要保留原来的列表,或者想把反转后的结果赋值给新变量,用切片。
my_list = [1, 2, 3, 4, 5]
new_list = my_list[::-1]
print(my_list) # [1, 2, 3, 4, 5] (原列表不变)
print(new_list) # [5, 4, 3, 2, 1] (新的反转列表)
# 方法 3:使用内置函数 reversed()(返回迭代器)
# 这个函数不会修改原列表,也不会立刻生成新列表,而是返回一个迭代器。如果你只是需要遍历反转后的元素(比如放在 for 循环里),用它最节省内存。
my_list = [1, 2, 3, 4, 5]
# 直接遍历
for item in reversed(my_list):
print(item, end=" ") # 输出: 5 4 3 2 1
# 如果确实需要变成一个新的列表,可以加上 list() 转换
new_list = list(reversed(my_list))
列表生成器和列表生成式的区别
列表生成式:的准确叫法是列表推导式。使用 []。它会立刻执行,并在内存中生成一个完整的列表(List)。
列表生成器:指生成器,通过生成器表达式来实现。使用 ()。它不会立刻执行,而是返回一个生成器对象。
# 列表推导式
list_comp = [x**2 for x in range(5)]
print(list_comp) # 输出: [0, 1, 4, 9, 16] (直接得到完整的列表)
print(type(list_comp)) # <class 'list'>
# 后面还可以加判断
even_numbers = [x for x in range(1, 101) if x % 2 == 0]
print(even_numbers) # 生成 1 到 100 的列表,并过滤出偶数
# 生成器表达式
gen_exp = (x**2 for x in range(5))
print(gen_exp) # 输出: <generator object <genexpr> at 0x...> (得到一个生成器对象)
print(type(gen_exp)) # <class 'generator'>
内存占用的区别(最核心的区别)
- 列表推导式:一次性把所有数据加载到内存中。如果数据量极大(比如一千万条数据),会导致内存瞬间飙升,甚至引发内存溢出(OOM)。
- 生成器表达式:惰性求值(Lazy Evaluation)。它只在内存中保存算法,当你通过 next() 或 for 循环向它要数据时,它才会“按需生产”下一个数据。无论数据量多大,内存占用几乎恒定。
使用场景的区别
- 用列表推导式 [] 的情况:数据量不大,且你需要多次访问这些数据,或者需要用到列表特有的方法(如 len()、切片 [:]、sort() 等)。
- 用生成器表达式 () 的情况:数据量非常大,且你只需要遍历一次(比如用来做求和、找最大值,或者直接传给其他函数处理)。
创建生成器的方式
- 生成器表达式:返回一个生成器对象,按需生产。gen_exp = (x**2 for x in range(5))
- 生成器函数:它的标志是函数里包含 yield 关键字。
# 生成器函数核心原理:当函数执行到 yield 时,会返回一个值,并且暂停(挂起)函数的执行,保留当前的所有状态。下一次调用 next() 时,函数会从 yield 暂停的地方继续往下执行,而不是从头开始。
def countdown(n):
print(">>> 倒计时开始!")
while n > 0:
yield n # 返回 n,并暂停在这里
n -= 1 # 下次调用时,从这里继续往下执行
print(">>> 倒计时结束!")
# 获取生成器对象
timer = countdown(3)
# 手动触发
print(next(timer)) # 输出: >>> 倒计时开始! \n 3
print(next(timer)) # 输出: 2
print(next(timer)) # 输出: 1
# print(next(timer)) # 再调用会报错: StopIteration
-
生成器的进阶用法
① send(value):向生成器内部传值
普通的 next() 相当于 send(None)。send() 可以在恢复执行的同时,把值赋给 yield 表达式。def accumulator(): total = 0 while True: value = yield total # 接收外部传入的值,并返回当前的 total total += value acc = accumulator() next(acc) # 必须先启动生成器(走到第一个 yield 暂停) print(acc.send(10)) # 输出: 10 print(acc.send(20)) # 输出: 30② throw(type, value):向生成器内部抛出异常
可以在生成器内部捕获异常,实现优雅的错误处理或提前终止。def my_gen(): try: yield 1 yield 2 except ValueError: print("捕获到内部异常!") yield "Error Handled" g = my_gen() print(next(g)) # 1 print(g.throw(ValueError, "出错了")) # 捕获到内部异常! \n Error Handled③ close():关闭生成器
调用后,生成器会抛出 GeneratorExit 异常并彻底停止,后续再调用 next() 就会报错。g = (x for x in range(10)) next(g) # 0 g.close() # 关闭 # next(g) # 报错: StopIteration
return 和 yeild 有什么区别
它们的核心区别在于:return 是“结束并返回”,而 yield 是“暂停并产出”。
1.函数的性质与返回值
- 使用 return:这是一个普通的函数。当执行到 return 时,函数会彻底结束,并将 return 后面的值作为结果返回给调用者。
- 使用 yield:这就变成了一个生成器函数(Generator Function)。它不会真正返回一个具体的值,而是返回一个生成器对象(Iterator)。
2.执行流程(最核心的区别)
- return:执行到这一行,函数生命周期结束。下次再调用这个函数时,会从头开始重新执行。
- yield:执行到这一行,函数会暂停(挂起),把 yield 后面的值吐出来,并且记住当前的所有内部状态(包括局部变量、执行位置等)。下次通过 next() 调用时,它会从上次暂停的地方继续往下执行,而不是从头开始。
总结:什么时候用哪个?
用 return:当你只需要一个最终结果,且数据量不大,函数执行完就不需要保留状态时。(99% 的日常开发场景)
用 yield:当你需要按需生成一系列数据,数据量极大(省内存),或者需要实现无限序列、状态机、协程等复杂逻辑时。

浙公网安备 33010602011771号