python中j real,RealPython 基础教程:Python 中的列表和元组

4,list 可以嵌套

我们知道,list 中可以包含任意种类的对象,这其中就包括 list 类型的对象。

list 可以包含子 list,子 list 中还可以包含自己的子 list,如此这般,可以嵌套至任意深度。

看下边这个例子:>>> x = ['a', ['bb', ['ccc', 'ddd'], 'ee', 'ff'], 'g', ['hh', 'ii'], 'j']>>> x['a', ['bb', ['ccc', 'ddd'], 'ee', 'ff'], 'g', ['hh', 'ii'], 'j']

x 指向的对象的结构可用下图表示:

217166297_3_20210308024542865_wm

x[0]、x[2] 和 x[4] 都是长度为 1 的字符串:>>> print(x[0], x[2], x[4])a g j

x[1] 和 x[3] 是 x 的子 list:>>> x[1]['bb', ['ccc', 'ddd'], 'ee', 'ff']>>> x[3]['hh', 'ii']

子 list 中的元素也可以通过索引语法来访问,只需要追加额外的 [] 包含的索引即可。>>> x[1]['bb', ['ccc', 'ddd'], 'ee', 'ff']>>> x[1][0]'bb'>>> x[1][1]['ccc', 'ddd']>>> x[1][2]'ee'>>> x[1][3]'ff'>>>>>> x[3]['hh', 'ii']>>> print(x[3][0], x[3][1])hh ii

可以看到,x[1][1] 又是一个子 list,再增加一个索引就可以访问其中的元素:>>> x[1][1]['ccc', 'ddd']>>> print(x[1][1][0], x[1][1][1])ccc ddd

你可以定义任意嵌套深度的 list,当然,嵌套越深,访问起来也越复杂。

常见的索引和切片操作同样适用于子 list。>>> x[1][1][-1]'ddd'>>> x[1][1:3][['ccc', 'ddd'], 'ee']>>> x[3][::-1]['ii', 'hh']

需要注意的是,list 上的运算符和函数操作仅作用在你指定的层级,它们不会递归应用在子 list 上。

我们以 len() 和 in 为例,看一下存在子 list 时的操作结果。>>> x['a', ['bb', ['ccc', 'ddd'], 'ee', 'ff'], 'g', ['hh', 'ii'], 'j']>>> len(x)5>>>>>> 'ddd' in xFalse>>> 'ddd' in x[1]False>>> 'ddd' in x[1][1]True

len(x) 只返回 x 第一级的元素个数,不会包含子 list 中元素的数目;in 同样只判断 'ddd' 是否存在于右操作数所在的那一层级,不会在子 list 中递归查找。

5,list 是可变的

我们前边介绍的大部分数据类型都是原子类型。比如,整数或浮点数对象都是不可再分割的原始单元。这些类型是不可变的,意味着对象一旦被赋值就无法再次改变其内容。在 Python 中考虑改变一个整数的值没多大意义,如果你想要一个其他值的整数,再创建一个整数对象并为其赋值就行了。

和整数、浮点数有点不一样,字符串是一个复合类型。字符串可以被分拆为更小的部分:单个字符。看起来,修改字符串中某个字符的值是有意义的。但事实是,你无法改变字符串中单个字符的值。Python 中的字符串也是不可变的。

list 是我们遇到的第一个可变数据类型。list 对象创建之后,我们可向其中随意地添加、删除、变换和移动元素。Python 提供了很多方式用来修改 list。

5.1 修改 list 中单个元素的值

list 中单个元素的值可通过索引与简单赋值来替换。>>> a = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge']>>> a['foo', 'bar', 'baz', 'qux', 'quux', 'corge']>>> a[2] = 10>>> a[-1] = 20>>> a['foo', 'bar', 10, 'qux', 'quux', 20]

而字符串中的单个字符却无法被替换。>>> s = 'foobarbaz'>>> s[2] = 'x'Traceback (most recent call last):File "", line 1, in TypeError: 'str' object does not support item assignment

可通过 del 命令删除 list 中的元素。>>> a = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge']>>> del a[3]>>> a['foo', 'bar', 'baz', 'quux', 'corge']

5.2 修改 list 中多个元素的值

Python 支持通过切片赋值语法来同时修改 list 中的多个连续元素。a[m:n] =

我们暂时可将此处的 iterable 当做是一个 list。这个赋值操作会将 a 中的 [m:n] 片段整体替换为 iterable。>>> a = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge']>>> a[1:4]['bar', 'baz', 'qux']>>> a[1:4] = [1.1, 2.2, 3.3, 4.4, 5.5]>>> a['foo', 1.1, 2.2, 3.3, 4.4, 5.5, 'quux', 'corge']>>> a[1:6][1.1, 2.2, 3.3, 4.4, 5.5]>>> a[1:6] = ['Bark!']>>> a['foo', 'Bark!', 'quux', 'corge']

iterable 中元素的个数不需要和 a[m:n] 片段中元素的个数相等。Python 会根据需要自动伸缩 list。

我们可以用多个元素来替换 list 中的一个元素,只需要将 [m:n] 切片指定为需要替换的单元素片段即可。a = [1, 2, 3]>>> a[1:2] = [2.1, 2.2, 2.3]>>> a[1, 2.1, 2.2, 2.3, 3]

注意,这和将 list 单个元素替换为另一个 list 对象不同!a = [1, 2, 3]>>> a[1] = [2.1, 2.2, 2.3]>>> a[1, [2.1, 2.2, 2.3], 3]

我们也可以在 list 上执行纯粹的插入操作:插入元素而不移除其他元素。这可通过将切片索引范围设置为插入位置的索引且长度为0即可:[n:n],n 为插入位置索引。>>> a = [1, 2, 7, 8]>>> a[2:2] = [3, 4, 5, 6]>>> a[1, 2, 3, 4, 5, 6, 7, 8]

有两种方法可用来删除 list 中的多个连续元素。

给要删除的切片赋值为一个空的 list:>>> a = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge']>>> a[1:5] = []>>> a['foo', 'corge']

通过 del 命令删除 list 切片:>>> a = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge']>>> del a[1:5]>>> a['foo', 'corge']

5.3 向 list 中前插或追加元素

可通过连接(+)或增量赋值(+=)运算符向 list 中前插或追加元素。>>> a = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge']>>> a += ['grault', 'garply']>>> a['foo', 'bar', 'baz', 'qux', 'quux', 'corge', 'grault', 'garply']>>>>>> a = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge']>>> a = [10, 20] + a>>> a[10, 20, 'foo', 'bar', 'baz', 'qux', 'quux', 'corge']

注意,用于和 list 执行连接操作的对象也必须是 list 类型。因此,如果想在 list 中添加一个元素,你需要通过单例 list (只含有一个元素)的方式来包装这个元素。>>> a = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge']>>> a += 20Traceback (most recent call last):File "", line 1, in TypeError: 'int' object is not iterable>>>>>> a += [20]>>> a['foo', 'bar', 'baz', 'qux', 'quux', 'corge', 20]

补充说明一点。

技术上讲,必须用另一个 list 和源 list 做连接,这个说法并不太正确。更精确的说法是,和源 list执行连接操作的对象必须是一个 iterable。当然,list 本身就是 iterable,因此 list 可被用于和另一个 list 对象进行连接。

字符串也是 iterable。但是,请看一下将字符串连接到 list 对象上时会发生什么。>>> a = ['foo', 'bar', 'baz', 'qux', 'quux']>>> a += 'corge'>>> a['foo', 'bar', 'baz', 'qux', 'quux', 'c', 'o', 'r', 'g', 'e']

结果可能和你想象的不太一样。

当字符串被迭代遍历时,其结果是一个字符组成的 list。

在上边这个例子中,连接到 list a 的对象也是一个 list:[ 'c', 'o', 'r', 'g', 'e']。

如果你真要往 list 尾部添加一个字符串对象,你需要将这个字符串包装到一个单例 list 中。>>> a = ['foo', 'bar', 'baz', 'qux', 'quux']>>> a += ['corge']>>> a['foo', 'bar', 'baz', 'qux', 'quux', 'corge']

5.4 用于修改 list 的方法

Python 提供了一些内置的方法用于修改 list。

下面介绍这些方法,假如 a 是一个 list 对象。

a.append():在 list 尾部追加一个对象。>>> a = ['a', 'b']>>> a.append(123)>>> a['a', 'b', 123]

请记住:list 方法原地操作目标 list 对象,这些方法不会返回新的 list 对象。>>> a = ['a', 'b']>>> x = a.append(123)>>> print(x)None>>> a['a', 'b', 123]

我们在上边的 list 连接操作时提到,通过连接(+)运算符将 iterable 连接到 list 对象时,iterable 中的元素会被打散,并逐个连接到 list 中。>>> a = ['a', 'b']>>> a + [1, 2, 3]['a', 'b', 1, 2, 3]>>> [1, 2, 3] + a[1, 2, 3, 'a', 'b']

a.append() 方法并非如此工作。如果一个 iterable 通过 a.append() 被追加到 list a 中,这个 iterable 会被视为一个单独的对象。>>> a = ['a', 'b']>>> a.append([1, 2, 3])>>> a['a', 'b', [1, 2, 3]]

因此,可以使用 append() 方法将字符串作为一个单独的实体追加到 list 中。>>> a = ['a', 'b']>>> a.append('foo')>>> a['a', 'b', 'foo']

a.extend():使用 iterable 中的元素来扩展 list 对象。

这个方法同样用于在 list 尾部追加元素,和 a.append() 不同的是,它将 iterable 中的元素逐个追加到 list 尾部,这和连接(+)运算符相似,确切的说,它和增量(+=)运算符行为是一致的。>>> a = ['a', 'b']>>> a.extend([1, 2, 3])>>> a['a', 'b', 1, 2, 3]>>>>>> a = ['a', 'b']>>> a += [1, 2, 3]>>> a['a', 'b', 1, 2, 3]

a.insert(, ):向 list 中插入一个对象。

a.insert(, ) 将对象 obj 插入到 list a 的 index 指定的位置。>>> a = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge']>>> a.insert(3, 3.14159)>>> a[3]3.14159>>> a['foo', 'bar', 'baz', 3.14159, 'qux', 'quux', 'corge']

a.remove():从 list 中移除一个对象。

将对象 obj 从 list a 中删除。若 a 中存在多个值和 obj 相等的对象,每次只删除一个;若 a 中不存在 obj,将触发异常。>>> a = ['foo', 'bar', 'baz', 'qux', 'bar', 'quux', 'corge']>>> a.remove('bar')>>> a['foo', 'baz', 'qux', 'bar', 'quux', 'corge']>>> a.remove('babala')Traceback (most recent call last):File "", line 1, in ValueError: list.remove(x): x not in list

a.pop(index = -1):从 list 中移除一个元素。

这个方法和 a.remove() 有两点不同:传入的参数为待删除对象的索引,而不是对象本身

该方法会返回被删除的对象

若未指定参数 index 的值,默认删除 list 的尾元素。>>> a = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge']>>> a.pop()'corge'>>> a['foo', 'bar', 'baz', 'qux', 'quux']>>>>>> a.pop()'quux'>>> a['foo', 'bar', 'baz', 'qux']

若指定了 index 的值,位于 index 的元素会被删除并被返回。

index 可以是负值。>>> a = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge']>>> a.pop(1)'bar'>>> a['foo', 'baz', 'qux', 'quux', 'corge']>>>>>> a.pop(-3)'qux'>>> a['foo', 'baz', 'quux', 'corge']

index 默认为 -1,因此,a.pop(-1) 等同于 a.pop()。

6,list 是动态的

从上边几个特性的讲解中,我们已经可以认识到,list 是随着各种操作而动态变化的,它会自行伸缩。>>> a = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge']>>> a[2:2] = [1, 2, 3]>>> a += [3.14159]>>> a['foo', 'bar', 1, 2, 3, 'baz', 'qux', 'quux', 'corge', 3.14159]>>>>>> a[2:3] = []>>> del a[0]>>> a['bar', 2, 3, 'baz', 'qux', 'quux', 'corge', 3.14159]

【Python 中的元组(tuple)】

tuple 是 Python 提供的另一个有序对象集合数据类型。

1,定义和使用 tuple

tuple 在各方面和 list 都是相同的,除了下边这两个属性:Python 使用圆括号(())来定义 tuple 对象

tuple 对象是不可变的

下边给出一个简短的例子来展示 tuple 的定义、索引和切片。>>> t = ('foo', 'bar', 'baz', 'qux', 'quux', 'corge')>>> t('foo', 'bar', 'baz', 'qux', 'quux', 'corge')>>>>>> t[0]'foo'>>> t[-1]'corge'>>> t[1::2]('bar', 'qux', 'corge')

通过切片来反转字符串和 list 的操作也适用于 tuple。>>> t[::-1]('corge', 'quux', 'qux', 'baz', 'bar', 'foo')

如同 list,tuple 对象也是有序的,可包含任意对象,可通过索引访问,可进行切片操作,也可以嵌套定义。

tuple 和 list 最大的不同在于:tuple 对象不能被修改!>>> t = ('foo', 'bar', 'baz', 'qux', 'quux', 'corge')>>> t[2] = 'Bark!'Traceback (most recent call last):File "", line 1, in TypeError: 'tuple' object does not support item assignment

那么,为什么要使用 tuple 而非 list 呢?在包含相同的元素的情况下,操作一个 tuple 要比 list 快些,这个速度上的差别可能在元素很多时比较显著。

有时候,处于业务上的需要,我们不希望数据被修改。这时候,tuple 从语法层面为我们提供了保障。

Python 有一个数据类型为字典(dict,后续会介绍到),它的部分组件要求其值是不可变的。tuple 可满足此需求,而 list 不能。

Python 解释器命令行中可以同时输入并显示若干变量,观察输出结果,你会发现,这组变量被隐式解释为一个 tuple 对象了。>>> a = 'foo'>>> b = 42>>> a, 3.14159, b('foo', 3.14159, 42)

当定义一个 tuple 对象时,有一点需要注意。

如果你定义的是一个空的或者包含两个或更多个元素的 tuple 时,Python 会清楚地明白你的意图,正确创建一个 tuple 对象。>>> t = ()>>> type(t)>>>>>> t = (1, 2)>>> type(t)>>> t = (1, 2, 3, 4, 5)>>> type(t)

但是,如果定义只包含一个元素的 tuple 对象呢?>>> t = (2)>>> type(t)>>>>>> t = ('hello')>>> type(t)

出现这种结果的原因是,在 Python 中圆括号也被用于定义表达式中各运算符的优先级。(2) 和 ('hello') 均被视为一个表达式,Python 计算其值,分别创建了一个整数对象和一个字符串对象。

如果你真想定义一个只包含一个元素的 tuple,不要忘了在元素之后追加一个逗号(,)。>>> t = (2,)>>> type(t)>>> t[0]2

当你在 Python 解释器命令行中输出一个单例 tuple 时,Python 解释器也会显示元素后边的逗号,以提示这是一个 tuple 对象。>>> print(t)(2,)

2,tuple 的赋值、打包(pack) 和 解包(unpack)

我们已经知道,一个包含若干元素的 tuple 字面量可以被赋值给一个对象。>>> t = ('foo', 'bar', 'baz', 'qux')

这个赋值操作好比将 tuple 中的这些元素打包到一个对象中。

217166297_4_20210308024542990_wm>>> t('foo', 'bar', 'baz', 'qux')>>> t[0]'foo'>>> t[-1]'qux'

如果这个打包的对象后续被赋值给一个新的 tuple,这些元素会被逐个解包到新 tuple 中的对象中。

217166297_5_2021030802454352_wm>>> (s1, s2, s3, s4) = t>>> s1'foo'>>> s2'bar'>>> s3'baz'>>> s4'qux'

使用解包语法时,左侧变量的个数必须和右侧 tuple 中元素的个数匹配。>>> (s1, s2, s3) = tTraceback (most recent call last):File "", line 1, in ValueError: too many values to unpack (expected 3)>>>>>> (s1, s2, s3, s4, s5) = tTraceback (most recent call last):File "", line 1, in ValueError: not enough values to unpack (expected 5, got 4)

打包和解包可以在一个语句中组合使用,从而产生一个复合赋值操作。>>> (s1, s2, s3, s4) = ('foo', 'bar', 'baz', 'qux')>>> s1'foo'>>> s2'bar'>>> s3'baz'>>> s4'qux'

在这种情形的赋值和少数其他的使用场景中,Python 允许省略通常用于表示 tuple 的圆括号。>>> t = 1, 2, 3>>> t(1, 2, 3)>>>>>> x1, x2, x3 = t>>> x11>>> x22>>> x33>>>>>> x1, x2, x3 = 4, 5, 6>>> x1, x2, x3(4, 5, 6)>>>>>> t = 2,>>> t(2,)

有无圆括号都可以正常工作,但为便于理解,尽量还是使用圆括号。

tuple 赋值操作可以产生一些有点奇怪却更地道的 Python 代码。

我们在编程中经常需要交换两个变量的值。在大多数编程语言中,你需要将一个变量存储到一个临时变量中。用代码表示为:>>> a = 'foo'>>> b = 'bar'>>> a,b('foo', 'bar')>>>>>> tmp = a>>> a = b>>> b = tmp>>>>>> a,b('bar', 'foo')

在 Python 中,我们可以使用一条语句完成交换操作。>>> a = 'foo'>>> b = 'bar'>>> a, b('foo', 'bar')>>>>>> a,b = b,a>>>>>> a,b('bar', 'foo')

相比使用临时变量,这的确是一个更现代的技术进步。

【结语】

本文详细介绍了 list 和 tuple 的基本属性和使用方法,你将会在 Python 程序中大量使用这两个数据结构。

接下来,我们会学习 Python 中另一个重要的数据类型:字典(dict)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值