来自“专业人士笔记”:创帆云:Python成为专业人士笔记--强烈建议收藏!每日持续更新!zhuanlan.zhihu.com
Python列表是Python程序中广泛使用的一种通用数据结构。它们可以在其他语言中找到,通常称为动态数组。它们都是可变的,并且是有序数据类型,允许对它们进行索引。列表可以包含不同类型的对象,也可以嵌套列表对象。
列表操作
从给定的列表a开始 :
a = [1, 2, 3, 4, 5]
1、append(value) – 将新元素附加到列表的末尾
# 将值6、7和7追加到列表
a.append(6)
a.append(7)
a.append(7)
#输出:a: [1, 2, 3, 4, 5, 6, 7, 7] 列表可以有重复值
# 追加另一个列表
b = [8, 9]
a.append(b)
#输出:a: [1, 2, 3, 4, 5, 6, 7, 7, [8, 9]]
# 附加不同类型的元素,因为列表元素不需要具有相同的类型 have the same type
my_string = "hello world"
a.append(my_string)
#输出:a: [1, 2, 3, 4, 5, 6, 7, 7, [8, 9], "hello world"]
注意,append()方法只将一个新元素追加到列表的末尾。如果将一个列表追加到另一个列表,则追加的列表将成为第一个列表末尾的单个元素。
#A 将一个列表附加到另一个列表
a = [1, 2, 3, 4, 5, 6, 7, 7]
b = [8, 9]
a.append(b)
#输出:a: [1, 2, 3, 4, 5, 6, 7, 7, [8, 9]]
a[8]
#输出: [8,9]
2、extend(enumerable) – 通过附加来自另一个枚举的元素来扩展列表。
a = [1, 2, 3, 4, 5, 6, 7, 7]
b = [8, 9, 10]
# 通过附加所有元素从b 扩展列表
a.extend(b)
#输出:a: [1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10]
#使用非列表枚举的元素扩展列表
a.extend(range(3))
#输出:a: [1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10, 0, 1, 2]
列表也可以与+运算符连接起来。注意,这不会修改任何原始列表
a = [1, 2, 3, 4, 5, 6] + [7, 7] + b
#输出:a: [1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10]
3、index(value, [startIndex]) – 获取输入值第一次出现的索引。如果输入值不在列表中,则会引发ValueError异常。如果提供了第二个参数,则从指定的索引处开始搜索。
a = [1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10]
a.index(7)
#输出: 6
a.index(49) # ValueError, 因为49不在a中
a.index(7, 7)
#输出: 7
a.index(7, 8) # ValueError, 因为从索引8开始,根本没有值
4、insert(index, value) – 将值插入到指定的索引之前。因此,在插入之后,新元素占据位置索引
a.insert(0, 0)
# 在索引0处插入数值0
a.insert(2, 5)
#在索引2处插入数值5
#输出:a: [0, 1, 5, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10]
5、pop([index]) – 删除并返回索引处的项。在没有参数的情况下,它删除并返回列表的最后一个元素
a= [0, 1, 5, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10]
a.pop(2)
#输出: 5
a.pop(8)
#输出: 7
#a变为:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 不带参数:
a.pop()
#输出: 10
#a变为 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
6、remove(value) – 删除指定值的第一个匹配项(注意是按值删除,不是按索引)。如果无法找到提供的值,则会引发ValueError 。
a= [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
a.remove(0)
a.remove(9)
#输出:a: [1, 2, 3, 4, 5, 6, 7, 8]
a.remove(10)
ValueError, 因为a列表里面没有10这个数值
7、reverse() – 反转列表并返回None。
a=[1, 2, 3, 4, 5, 6, 7, 8]
a.reverse()
#输出: [8, 7, 6, 5, 4, 3, 2, 1]
8、count(value) – 计算某个值在列表中出现的次数。
a= [0, 1, 5, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10]
a.count(7)
#输出: 2
9、sort() – 按数字和字典顺序对列表进行排序,并返回None。
a.sort()
a = [1, 2, 3, 4, 5, 6, 7, 8]
#按数字顺序排列列表了
当使用sort()方法中的reverse=True标志对列表进行排序时,列表也可以被反转
a = [1, 2, 3, 4, 5, 6, 7, 8]
a.sort(reverse=True)
a = [8, 7, 6, 5, 4, 3, 2, 1]
如果希望根据项的属性排序,可以使用key关键字参数
import datetime
class Person(object):
def __init__(self, name, birthday, height):
self.name = name
self.birthday = birthday
self.height = height
def __repr__(self):
return self.name
l = [Person("John Cena", datetime.date(1992, 9, 12), 175),
Person("Chuck Norris", datetime.date(1990, 8, 28), 180),
Person("Jon Skeet", datetime.date(1991, 7, 6), 185)]
l.sort(key=lambda item: item.name)
#输出l: [Chuck Norris, John Cena, Jon Skeet]
l.sort(key=lambda item: item.birthday)
#输出l: [Chuck Norris, Jon Skeet, John Cena]
l.sort(key=lambda item: item.height)
#输出l: [John Cena, Chuck Norris, Jon Skeet]
如果是字典列表,处理的方法是一样的:
import datetime
l = [{'name':'John Cena', 'birthday': datetime.date(1992, 9, 12),'height': 175},
{'name': 'Chuck Norris', 'birthday': datetime.date(1990, 8, 28),'height': 180},
{'name': 'Jon Skeet', 'birthday': datetime.date(1991, 7, 6), 'height': 185}]
l.sort(key=lambda item: item['name'])
#输出:l: [Chuck Norris, John Cena, Jon Skeet]
l.sort(key=lambda item: item['birthday'])
#输出l: [Chuck Norris, Jon Skeet, John Cena]
l.sort(key=lambda item: item['height'])
#输出:l: [John Cena, Chuck Norris, Jon Skeet]
按子字典排序:
import datetime
l = [{'name':'John Cena', 'birthday': datetime.date(1992, 9, 12),'size': {'height': 175,
'weight': 100}},
{'name': 'Chuck Norris', 'birthday': datetime.date(1990, 8, 28),'size' : {'height': 180,
'weight': 90}},
{'name': 'Jon Skeet', 'birthday': datetime.date(1991, 7, 6), 'size': {'height': 185,
'weight': 110}}]
l.sort(key=lambda item: item['size']['height'])
#输出l: [John Cena, Chuck Norris, Jon Skeet]
使用attrgetter和itemgetter进行排序的更好方法
还可以使用操作符模块中的attrgetter和itemgetter函数对列表进行排序。这些可以帮助提高可读性和可重用性。这里有一些例子
from operator import itemgetter,attrgetter
people = [{'name':'chandan','age':20,'salary':2000},
{'name':'chetan','age':18,'salary':5000},
{'name':'guru','age':30,'salary':3000}]
by_age = itemgetter('age')
by_salary = itemgetter('salary')
people.sort(key=by_age) # 按年龄排序
people.sort(key=by_salary) #按薪水排序
itemgetter也可以被赋给一个索引。如果您希望根据元组的索引进行排序,这是很有帮助的。
list_of_tuples = [(1,2), (3,4), (5,0)]
list_of_tuples.sort(key=itemgetter(1))
print(list_of_tuples) #输出:[(5, 0), (1, 2), (3, 4)]
如果希望根据对象的属性排序,请使用attrgetter :
class Person(object):
def __init__(self, name, birthday, height):
self.name = name
self.birthday = birthday
self.height = height
def __repr__(self):
return self.name
persons = [Person("John Cena", datetime.date(1992, 9, 12), 175),
Person("Chuck Norris", datetime.date(1990, 8, 28), 180),
Person("Jon Skeet", datetime.date(1991, 7, 6), 185)]
#例子:
person.sort(key=attrgetter('name')) #按 name 排序
by_birthday = attrgetter('birthday')
person.sort(key=by_birthday) #按生日排序
10、clear() – 从列表中删除所有项
a.clear()
#a = []
11、列表乘法 – 将现有列表乘以一个整数将生成一个更大的列表,其中包含原始列表的多个副本。这对于列表初始化很有用
b = ["blah"] * 3
# 输出 ["blah", "blah", "blah"]
b = [1, 3, 5] * 5
#输出 [1, 3, 5, 1, 3, 5, 1, 3, 5, 1, 3, 5, 1, 3, 5]
12、del关键字 – 可以使用del关键字和切片表示法删除列表中的多个元素
a = list(range(10))
#值:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
del a[::2]
#输出 [1, 3, 5, 7, 9] 遍历列表所有的值,按照步长为2取出值
del a[-1]
#输出 [1, 3, 5, 7] 删除倒数第1个
del a[:]
#输出:[]
13、列表复制
默认的赋值“=”将原始列表的引用分配给新名称。也就是说,原变量名和新变量名都指向相同的list对象。通过其中任何一个做出的改变都将反映在另一个变化中。这通常不是你想要的。
b = a
a.append(6)
# b: [1, 2, 3, 4, 5, 6]
如果你想创建一个列表的副本,你可以这样做:
new_list = old_list[:]
也可以使用 内建的list()函数 :
new_list = list(old_list)
也可以使用模块函数copy.copy():
import copy
new_list = copy.copy(old_list)
这比list()稍微慢一些,因为它必须首先找出旧list的数据类型。如果列表包含对象,并且您也想要复制它们,那么使用通用的copy.deepcopy()
import copy
new_list = copy.deepcopy(old_list)
在python3版本以上,copy函数可以直接返回列表的拷贝:
aa = a.copy()
#aa = [1, 2, 3, 4, 5]
访问列表值
Python列表是从零开始索引的,在其他语言中就像数组一样。
lst = [1, 2, 3, 4]
lst[0]
#1
lst[1]
#2
试图访问列表范围之外的索引将引发一个IndexError错误
lst = [1, 2, 3, 4]
lst[4]
#注意:索引从0开始,IndexError: list index out of range
负数被解释为从列表的末尾开始计数。
lst = [1, 2, 3, 4]
lst[-1]
#4
lst[-2]
#3
lst[-5]
#IndexError: list index out of range
这在功能上等效于 :
lst = [1, 2, 3, 4]
print(lst[len(lst)-1]) #len(lst)的长度为4,即lst[4-1]=lst[3]
# 输出:4
列表允许使用切片表示法选取数据:lst[start:end:step]。切片后输出是一个新列表,包含从索引start到end、步长为step的元素。如果省略了选项,则默认开始为列表的开始,结束为列表的结束,步长为1
lst = [1, 2, 3, 4]
lst[1:]
# [2, 3, 4]
lst[:3]
# [1, 2, 3] 注意:不包括索引3本身
lst[::2]
# [1, 3] 按步长为2取数
lst[::-1]
#[4, 3, 2, 1] 倒序按步长为1取数
lst[-1:0:-1]
# [4, 3, 2] 倒序按步长为1取数,但不包括索引0
lst[5:8]
# [] 因为起始索引大于lst的长度,所以返回空列表 list
lst[1:10]
#[2, 3, 4] 结束索引超过本身长度
高级切片
当列表被切片时,切片对象会调用列表对象的__getitem__()方法。Python有一个内建切片方法来生成切片对象。我们可以使用它来存储切片,然后像这样重用它:
data = 'chandan purohit 22 2000'
# 假设数据字段长度固定
name_slice = slice(0,19)
age_slice = slice(19,21)
salary_slice = slice(22,None)
#现在我们获得了多个切片
print(data[name_slice]) #chandan purohit
print(data[age_slice]) #'22'
print(data[salary_slice]) #'2000'
这可以通过在类中重写_getitem_来为对象提供切片功能,从而达到强大的自定义切片功能
检查列表是否为空
The emptiness of a list is associated to the boolean False, so you don’t have to check len(lst) == 0, but just lst
or not lst
列表的空值可以利用布尔值False处理,所以不必检查len(lst) == 0,只需检查是或否就可以:
lst = []
if not lst:
print("list is empty")
#输出: list is empty
迭代列表
Python支持直接在列表上使用for循环
my_list = ['foo', 'bar', 'baz']
for item in my_list:
print(item)
#输出: foo
#输出: bar
#输出: baz
您还可以同时获得每个项目的位置
my_list = ['foo', 'bar', 'baz']
for (index, item) in enumerate(my_list):
print('The item in position {} is: {}'.format(index, item))
#输出: The item in position 0 is: foo
#输出: The item in position 1 is: bar
#输出: The item in position 2 is: baz
另一种基于索引值迭代列表的方法 :
my_list = ['foo', 'bar', 'baz']
for i in range(0,len(my_list)):
print(my_list[i])
#输出:
foo
bar
baz
注意,在对列表进行迭代时更改列表中的项可能会产生意想不到的结果 :
my_list = ['foo', 'bar', 'baz']
for item in my_list:
if item == 'foo':
del my_list[0]
print(item)
#输出: foo
#输出: baz
在上面示例中,我们在第一次迭代时删除了第一项,但这导致跳过了bar。
检查元素是否在列表中
Python使检查项目是否在列表中非常简单。只需使用in操作符。
lst = ['test', 'twest', 'tweast', 'treast']
print('test' in lst)
#输出: True
print('toast' in lst)
#输出: False
注意:集合上的in操作符判断要比列表上的快。如果您需要在可能非常大的列表上多次使用它,最好把列表转换为一个集合,并在集合上去判断元素的存在性,这样性能可以提升很多
lst = ['test', 'twest', 'tweast', 'treast']
slst = set(lst)
print('test' in slst)
#输出: True
Any 和 All 关键字
您可以使用all()来确定一个迭代器中的所有值是否都为True
nums = [1, 1, 0, 1]
all(nums)
# False,因为其中有元素‘0’,其代表false
chars = ['a', 'b', 'c', 'd']
all(chars)
# True
同样,any()确定一个迭代器中的一个或多个值是否为True
nums = [1, 1, 0, 1]
any(nums)
# True 只要有一个True 整体返回就是True , '1'代表真值
vals = [None, None, None, False]
any(vals)
# False 很遗憾,None和False在python中都代表False,一个True都没有
虽然本例使用了一个列表,但需要注意的是,这些内置函数可以与任何可迭代的表达式生成器一起工作
vals = [1, 2, 3, 4]
any(val > 12 for val in vals)
# False
any((val * 2) > 6 for val in vals)
# True
反转列表元素
您可以使用反转函数,它将迭代并返回反转后的列表
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
rev = reversed(numbers)
print(list(rev))
#输出:[9, 8, 7, 6, 5, 4, 3, 2, 1]
注意,列表“numbers”在此操作中保持不变,并且保持与最初相同的顺序。要在适当的位置反转,可以使用reversed方法。您还可以通过使用切片语法将第三个参数(step)设置为-1来反转一个列表(实际上也是获得一个列表的副本,原始列表的元素顺序不受影响):
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
rev = numbers[::-1]
print(list(rev))
#输出:[9, 8, 7, 6, 5, 4, 3, 2, 1]
连接和合并列表
方法一: 连接list1和list2的最简单方法
merged = list1 + list2
方法二: zip返回一个元组列表,其中第i个元组包含来自每个参数序列或迭代的第i个元素 ;其优势是很容易获得一个二维数组:
alist = ['a1', 'a2', 'a3']
blist = ['b1', 'b2', 'b3']
for a, b in zip(alist, blist):
print(a, b)
#输出:
a1 b1
a2 b2
a3 b3
如果列表的长度不同,那么结果将只包含与最短列表长度相同的元素
alist = ['a1', 'a2', 'a3']
blist = ['b1', 'b2', 'b3', 'b4']
for a, b in zip(alist, blist):
print(a, b)
#输出:
a1 b1
a2 b2
a3 b3 #注意,blist的b4值丢失了
alist = []
len(list(zip(alist, blist)))
#输出:
0 #因为有个空列表, 会以长度最短的列表为主
对于长度不等的填充列表,使用itertools.zip_longest可以轻松搞定:
import itertools
alist = ['a1', 'a2', 'a3']
blist = ['b1']
clist = ['c1', 'c2', 'c3', 'c4']
for a, b, c in itertools.zip_longest(alist, blist, clist):
print(a, b, c)
# 输出:
# a1 b1 c1
# a2 None c2
# a3 None c3
# None None c4
方法三: 指定索引进行插入:
alist = [123, 'xyz', 'zara', 'abc']
alist.insert(3, [2009])
print("Final List :", alist)
#输出:
Final List : [123, 'xyz', 'zara', 2009, 'abc']
列表长度
使用len()来获得一个列表的一维长度
len(['one', 'two'])
#返回 2
len(['one', [2, 3], 'four'])
#返回 3, 而不是 4 注意是一维长度
len()也适用于字符串、字典和其他类似于列表的数据结构。注意,len()是一个内置函数,而不是list对象的方法。还要注意len()的计算复杂度是O(1),这意味着无论列表的长度是多少,获取列表的长度所花费的时间都是一样的。
删除列表重复值
可以通过将列表转换为集合,利用集合不能存储重复数据的特性来删除列表中的重复值。如果需要返回列表数据结构,那么可以使用函数list()将集合再转换回列表
names = ["aixk", "duke", "edik", "tofp", "duke"]
list(set(names))
#输出: ['duke', 'tofp', 'aixk', 'edik']
注意,将一个列表转换为一个集合后,原来的列表中元素的索引顺序将丢失。
要保持列表的顺序,可以使用OrderedDict
import collections
names = ["aixk", "duke", "edik", "tofp", "duke"]
print(list(collections.OrderedDict.fromkeys(names).keys()))
#输出: ['aixk', 'duke', 'edik', 'tofp']
列表的比较
可以使用比较运算符按字典顺序比较列表。运算符两边必须具有相同的数据类型。
[1, 10, 100] < [2, 10, 100]
#True, 因为 1 < 2
[1, 10, 100] < [1, 10, 100]
#False, 因为两个列表相等
[1, 10, 100] <= [1, 10, 100]
#True, 因为两个列表相等
[1, 10, 100] < [1, 10, 101]
#True, 因为 100 < 101
[1, 10, 100] < [0, 10, 100]
#False, 因为 0 < 1
如果其中一个列表包含了另外一个列表,则长度短的更小。
print([1, 10] < [1, 10, 100])
#输出:True
访问嵌套列表
从一个三维列表开始 :
alist = [[[1,2],[3,4]], [[5,6,7],[8,9,10], [12, 13, 14]]]
#开始访问数据
print(alist[0][0][1])
#输出:2
#访问了第一个列表中第一个列表中的第二个元素
print(alist[1][1][2])
#输出:10
#访问了第二个列表中的第二个列表中的第三个元素
执行添加操作:
alist[0][0].append(11)
print(alist[0][0][2])
# 11
# 在第一个列表的第一个列表的末尾追加了11
使用嵌套的for循环来打印列表
alist = [[[1,2,11],[3,4]], [[5,6,7],[8,9,10], [12, 13, 14]]]
for row in alist: # 一种循环遍历嵌套列表的方法
for col in row:
print(col)
#[1, 2, 11]
#[3, 4]
#[5, 6, 7]
#[8, 9, 10]
#[12, 13, 14]
请注意,此操作可以用于列表解析器,基于可应用于生成器,例如
alist = [[[1,2,11],[3,4]], [[5,6,7],[8,9,10], [12, 13, 14]]]
[col for row in alist for col in row] #里面有嵌套循环
# [[1, 2, 11], [3, 4], [5, 6, 7], [8, 9, 10], [12, 13, 14]]
另一种使用嵌套for循环的方法。这种方法更好,但其应用的场景多是因为需要在循环最里层同时要使用行和列的索引:
alist = [[[1,2,11],[3,4]], [[5,6,7],[8,9,10], [12, 13, 14]]]
for row in range(len(alist)): # 一种不那么python化的循环遍历列表的方法
for col in range(len(alist[row])):
print(alist[row][col])
#输出:
[1, 2, 11]
[3, 4]
[5, 6, 7]
[8, 9, 10]
15
[12, 13, 14]
嵌套列表的分片:
alist = [[[1,2,11],[3,4]], [[5,6,7],[8,9,10], 15,[12, 13, 14]]]
print(alist[1][1:])
#输出 [[8, 9, 10], 15, [12, 13, 14]]
#在多维列表中,分片仍然有效
固定数量的列表
my_list = [{'test'}] * 10
print(my_list)
#输出:[{'test'}, {'test'}, {'test'}, {'test'}, {'test'}, {'test'}, {'test'}, {'test'}, {'test'}, {'test'}]
#这时我需要在列表第一个元素上增加一个值:
my_list[0].add('test2');
print(my_list)
#输出:[{'test2', 'test'}, {'test2', 'test'}, {'test2', 'test'}, {'test2', 'test'}, {'test2', 'test'}, {'test2', 'test'}, {'test2', 'test'}, {'test2', 'test'}, {'test2', 'test'}, {'test2', 'test'}]
#居然全部增加了,这不是我想要的!
#如果这样申请一个列表
my_list=[{'test'} for _ in range(10)]
my_list[0].add('test2');
print(my_list)
#输出:[{'test', 'test2'}, {'test'}, {'test'}, {'test'}, {'test'}, {'test'}, {'test'}, {'test'}, {'test'}, {'test'}]
#这个是我想要的!
上面代码第一个错误的主要原因是,针对“ * ”号拷贝出来的列表,其内存引用是同一个,因此一旦进行操作所有的元素都会更新;这时可以通过其它语句生成不同内存引用的相同值,这里尤其要注意