咱们的gzh是向阳三只大明白,满满满是干货,分享近期的学习常识以及个人总结(包含读研和IT),希望我们一同尽力,一同加油!求重视!!

简介

【列表 (List) 】是 Python 中最基本的数据类型之一,列表中的每个元素均会分配一个数字,用以记载方位,咱们称之为 索引 ,索引值从 0 开端,顺次往后计数。

列表运用中括号【[]】包裹,元素之间运用逗号【,】 分隔,其元素能够是数字、字符串、列表等其他任何数据类型。

列表相同支持索引、更新、删去、嵌套、拼接、成员检查、截取、追加、扩展、排序等相关操作。

列表的每一个元素实质上存储的是一个指针,而不是数据本身。以下面一段做示例:

# 创立一个列表
x = [1, 2, 'a', [1, 2], 3, 4, 'b']
N = len(x)
for i in range(N):
    print(id(x[i]))
print(id(x[3][0]))
print(id(x[3][1])) 
----------------- 第一次运转 ---------------------
140706575156912
140706575156944
2389690352240
# 2389798127680
140706575156976
140706575157008
2389690295408
140706575156912
140706575156944
----------------- 第2次运转 ---------------------
140706575156912
140706575156944
2389690352240
# 2389798169600
140706575156976
140706575157008
2389690295408
140706575156912
140706575156944

由上面的示例能够看出针对数字、常见字符串,在Python发动的时分就已经分配好内存了,示例中的x,它在内存中的分布如下:

【Python学习003】高效数据结构-列表

常见列表操作

增加元素

append(self, __object: _T) -> None

append办法在列表结尾增加一个元素,相当于a[len(a):] = [x],示例如下:

nums = [1, 2, 3]
nums.append(4)
nums -> [1, 2, 3, 4]

扩展列表

extend(self, __iterable: Iterable[_T]) -> None

extend办法用可迭代目标的元素扩展列表。调用该办法相当于a[len(a):] = iterable,详细示例如下:

nums = [1, 2, 3]
nums_extend = [4, 5, 6]
nums.extend(nums_extend)
nums -> [1, 2, 3, 4, 5, 6]

刺进元素

insert(self, __index: SupportsIndex, __object: _T) -> None

insert办法用来在指定方位刺进元素。第一个参数是刺进元素的索引,因而,a.insert(0, x) 在列表开头刺进元素, a.insert(len(a), x) 等同于 a.append(x) ,详细示例如下:

nums = [1, 2, 3]
nums.insert(0, 5)
nums -> [5, 1, 2, 3]

按元素值删去

remove(self, __value: _T) -> None

remove办法用来从从列表中删去第一个值为 x 的元素。未找到指定元素时,触发 ValueError 异常,示例如下:

x = [1, 2, 3, 1]
x.remove(1)
x -> [2, 3, 1]

调用该办法会从左向右寻觅相等的元素,底层是调用传入目标的__eq__办法对列表中的所有目标进行比较,假如该办法回来True,则会删去该元素,示例如下:

class TestClass:
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age
    def __eq__(self, other):
        print(f"{self}调用eq办法")
        return self.name == other.name and self.age == other.age
    def __str__(self):
        return f"name:{self.name}, age:{self.age} "\
a1 = TestClass("a", 1)
a2 = TestClass("b", 2)
x = [a1, a2]
a3 = TestClass("b", 2)
x.remove(a3)
x
------------------------------
name:a, age:1 调用eq办法
name:b, age:2 调用eq办法
[<__main__.TestClass at 0x2dce1df8b80>]

当运用remove办法删去元素的时分需求留意当一个列表包含多个类型的元素的时分很容易犯错,传入目标的__eq__办法写的不好会发生许多问题,详细示例如下:

a1 = TestClass("a", 1)
a2 = TestClass("b", 2)
x = [1, a1, a2]
a3 = TestClass("b", 2)
x.remove(a3)
x -> AttributeError: 'int' object has no attribute 'name'

按方位进行删去

pop(self, __index: SupportsIndex = ...) -> _T

调用pop办法删去列表中指定方位的元素,并回来被删去的元素。未指定方位时,a.pop() 删去并回来列表的最后一个元素,详细示例如下:

x = [1, 2, 3]
x.pop()
x -> [1, 2]
x = [1, 2, 3]
x.pop(0)
x -> [2, 3]

铲除列表元素

clear(self) -> None

调用clear办法会删去列表里的所有元素,相当于 del a[:] ,详细示例如下:

x = [1, 2, 3]
x.clear()
x -> []

按索引回来元素

index(self, __value: _T, __start: SupportsIndex = ..., __stop: SupportsIndex = ...) -> int

调用index办法回来列表中第一个值为 x 的元素的零基索引。未找到指定元素时,触发 ValueError 异常。

可选参数 startend 是切片符号,用于将搜索限制为列表的特定子序列。回来的索引是相对于整个序列的开端核算的,而不是根据start 参数,详细示例如下:

x = [1, 2, 3]
x.index(2) -> 1

计算元素呈现次数

count(self, __value: _T) -> int

调用count办法会回来列表中元素 x 呈现的次数,详细示例如下:

x = [1, 2, 3, 1]
x.count(1) -> 2

元素原地排序

sort(self, *, key: Callable[[_T], SupportsRichComparison], reverse: bool = ...) -> None

调用sort办法就地排序列表中的元素,详细示例如下:

x = [1, 2, 3, 1]
x.sort(reverse=True)
x -> [3, 2, 1, 1]

翻转列表元素

reverse(self) -> None

调用reverse办法会翻转列表中的元素,详细示例如下:

x = [1, 2, 3]
x.reverse()
x -> [3, 2, 1]

浅复制

copy(self) -> list[_T]

调用copy办法回来列表的浅复制,相当于 a[:] ,关于浅复制和深复制,概况见【Python】python深复制和浅复制(一)。浅复制示例如下:

x = [1, [2, 3], 4]
y = x.copy()
y -> [1, [2, 3], 4]
y[1].append(5)
x -> [1, [2, 3, 5], 4]

符号操作

符号 阐明
+ 列表拼接
* 重复元素
in / not in 成员判别
[] 索引取值
x[start_index: end_index] 列表切片

详细示例如下:

# 列表拼接
x1 = [1, 2, 3]
x2 = [4, 5, 6]
x1 + x2 -> [1, 2, 3, 4, 5, 6]
# 重复元素,留意重复元素类似于浅复制之后再拼接
x = [1, 2, 3]
x * 3 -> [1, 2, 3, 1, 2, 3, 1, 2, 3]
x = [1, [2, 3], 4]
y = x * 3
y[1].append('other')
y -> [1, [2, 3, 'other'], 4, 1, [2, 3, 'other'], 4, 1, [2, 3, 'other'], 4]
# 成员判别
x = [1, 2, 3]
1 in x -> True
4 not in x -> True
# 列表切片,留意左闭右开
x = [1, 2, 3, 4, 5, 6]
x[1:4] -> [2, 3, 4]

列表的高阶完成

列表完成行列

行列的特点是先进先出,运用列表能够调用append办法增加元素,调用pop办法取出元素,示例如下:

x = []
x.append(1)
x.append(2)
x.append(3)
print(x.pop(0)) -> 1
print(x.pop(0)) -> 2

列表完成栈

栈的特点是后进先出,相同也可调用append办法和pop办法完成栈, 详细示例如下:

x = []
x.append(1)
x.append(2)
x.append(3)
print(x.pop()) -> 3
print(x.pop()) -> 2

可是列表作为行列的效率很低。因为在列表结尾增加和删去元素非常快,但在列表开头刺进或移除元素却很慢(因为所有其他元素都必须移动一位)。最好运用 【collections.deque】来完成行列,deque能够快速从两头增加或删去元素。

del句子

del 句子按索引,而不是值从列表中移除元素。与回来删去值的 pop() 办法不同, del 句子也能够从列表中移除切片,或清空整个列表,详细示例如下:

x = [1, 2, 3, 4, 5, 6]
del x[0]
x -> [2, 3, 4, 5, 6]
# 删去切片的时分留意左闭右开问题
x = [1, 2, 3, 4, 5, 6]
del x[1:3]
x -> [1, 4, 5, 6]

高效列表

运用列表推导式

列表推导式是一种生成列表的办法,比较与传统的列表生成在底层进行了优化,具有了更高的功能,列表推导式的详细优势如下:

  1. 具有更高的功能,先分配的内存再增加数据;

  2. 运用列表推导式语义上更加直观;

  3. 适用于类型转换、数据过滤;

传统办法

# 1亿数据
data = range(100000000)
%%timeit tmp = 0
some_list = list()
for i in data:
    some_list.append(i)
4.75 s  59.6 ms per loop (mean  std. dev. of 7 runs, 1 loop each)

运用列表推导式

# 1亿数据
data = range(100000000)
%%timeit tmp = 0
some_list = [i for i in data] 
3.26 s  29.6 ms per loop (mean  std. dev. of 7 runs, 1 loop each)

从上面的例子能够看出列表推导式节约了30%的运转时间,提高幅度已经很大了,跟着数据量的提高,列表推导式的功能提高还会更显著。

嵌套列表推导式

x = [[i for i in range(3)] for j in range(3)]
x -> [[0, 1, 2], [0, 1, 2], [0, 1, 2]]

列表推导式除了能够更快地构建列表,还能够执行一些简单的过滤,示例如下:

# 传统办法
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
odd_numbers = filter(lambda x: x%2 != 0, nums)
list(odd_numbers) ->[1, 3, 5, 7, 9]
# Pythonic办法
odd_numbers = [i for i in nums if i % 2 != 0]
odd_numbers -> [1, 3, 5, 7, 9]

运用all或any

  1. 当目标为空列表的时分,all办法的判别成果仍是True。

  2. 当目标为空列表的时分,any办法的判别成果是False。

all办法在数据量很大的状况下有一定的功能提高,比照示例如下:

def check(l: List[int]) -> bool:
    for i in l:
        if not i:
            return False
    return True
# 准备数据
data = range(100000000)
%%timeit tmp = 0
check(data) -> 67.3 ns  0.628 ns per loop (mean  std. dev. of 7 runs, 10,000,000 loops each)
%%timeit tmp = 0
all(data) -> 43 ns  0.998 ns per loop (mean  std. dev. of 7 runs, 10,000,000 loops each) 	

总结

  1. 列表作为 Python 最基本的数据类型之一,在工作中十分常用,一般与其他数据类型调配运用,用于构建数据结构;
  2. 界说列表可直接运用 [], 也可选择 list() 办法,假如从一个可迭代目标创立列表尽量运用列表推导式
  3. 列表能够完成行列,可是功能欠佳,最好运用【deque】来完成;
  4. 判别列表元素的时分能够考虑调用any或者all,而不是自己的

往期回忆

  1. 【Python学习002】函数参数

文中难免会呈现一些描绘不当之处(尽管我已重复检查多次),欢迎在留言区指正,相关的常识点也可进行分享。