(四)Python的字符串,列表和元组

前言

每一种语言都有其特定的数据类型,Python也不例外,这里我们再次看一下Python的字符串,以及列表、元组,Python的列表(list)、元组(tuple)和swift的数组、元组也十分相似。

Python的字符串

字符串的编码和解码

python中,常常会涉及到字符串的编码问题,对于单个字符编码,python提供了ord()函数来获取字符的整数表示,提供chr()函数来将编码转换成相应的字符。我们在交互式环境下来看看它们是怎样操作的。

ord()函数获取单个字符的整数形式:

>>> ord('a')
97
>>> ord('b')
98
>>> ord('x')
120
>>> ord('y')
121
>>> ord('牛')
29275

chr()函数将编码穿换成字符:

>>> chr(97)
'a'
>>> chr(98)
'b'
>>> chr(120)
'x'
>>> chr(121)
'y'
>>> chr(29275)
'牛'

从以上可以看出,对于单个字符来说,python提供的两个函数可以将对应的字符整数相互转换,来获取对于的编码值。

但是实际上,我们通常用到的还是Python的字符串str居中,而Pythonstr在计算机的内存中又是以Unicode(统一的字符编码标准)表示,一个字符对应若干个字节,如果在网络上传输或保存到磁盘,需要将str变为以字节为单位的bytes。那么转换成以字节(bytes)为单位后是怎样表示的呢?这就牵扯到Python编码解码了。

Python中,编码使用encode(), 解码使用decode()

>>> 'dog'.encode('ascii')
b'dog'
>>> '小狗'.encode('utf-8')
b'\xe5\xb0\x8f\xe7\x8b\x97'

所以,在Python中,编码之后的字节类型(bytes)是用带b字母的前缀的单引号或双引号来表示。

注意:编码的时候,如果是纯英文编码,要使用asciiutf-8编码;如果是包含中文,那么一定要使用目前统一的编码标准utf-8。因为ascii是一个字节,utf-8是1~6个字节,而一个中文的编码要大于1个字节,显然,中文编码使用ascii编码会超出ascii的编码范围,类似值溢出是一个道理。

例如,中文编码使用ascii编码就会报错

>>> '小狗'.encode('ascii')
Traceback (most recent call last):
  File "", line 1, in 
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

通过编码后,我们得到的就是字节(bytes), 那么,又怎么变为字符串呢?那就需要通过解码decode()操作。事实上,当我们从网络或磁盘上读取到了字节流(bytes)时,要变成字符串,我们就需要解码decode()

>>> b'dog'.decode('ascii')
'dog'
>>> b'\xe5\xb0\x8f\xe7\x8b\x97'.decode('utf-8')
'小狗'

现在,编码和解码都知道了,那么,如果我们想要知道一个字符串有几个字符怎么计算呢?字节又怎么计算呢?这时候,Python为我们提供了一个len()函数用来计算字符数和字节数。当所计算的是字符串时,就是字符数;当所计算的是字符串通过编码后的字节(bytes)时,计算的就是字节数。

// 计算字符数
>>> len('dog')
3
// 计算字节数
>>> len(b'dog')
3

// 计算字符数
>>> len('小狗')
2
// 计算字节数
>>> len(b'\xe5\xb0\x8f\xe7\x8b\x97')
6

所以,当用utf-8编码后,我们可以计算出一个中文在内存中占用3个字节,2个中文占用6个字节,而一个英文字母始终只占1个字节。

字符串的格式化

Python字符串的格式化有两种方式,一种就是使用%来格式化,同时赋予相应的占位符,比如:整数用%d、浮点数用%f、字符串用%s等,和C语言的占位符差不多,我们来看例子

>>> print('this is an integer: %d' % 99)
this is an integer: 99

>>> print('Hello, %s, you got scores: %f' % ('langke', 66.66))
Hello, langke, you got scores: 66.660000

为了保留2位小数,我们可以
>>> print('Hello, %s, you got scores: %.2f' % ('langke', 66.66))
Hello, langke, you got scores: 66.66

另外一种字符串格式化是字节用Python提供的函数format(), 同样来看例子

>>> print('Hello, {0}! I have abount {1} apples'.format('langke', 38))
Hello, langke! I have abount 38 apples
>>> print('It\'s {0}'.format(123456))
It's 123456
>>> print('result is {0:.3f}'.format(998.7809))
result is 998.781

Python的list

listPython中叫列表, 其实,我们完全可以称之为数组, 和swift中的数组一样,它是一个有序元素的集合,可以增、删、改、查的功能。

>>> names = ['Jhon', 'Alice', 'Bob', 'langke', '1', '2', '3']
>>> len(names)
7
>>> print(names)
['Jhon', 'Alice', 'Bob', 'langke', '1', '2', '3']

创建一个数组names, 并计算它的元素个数,计算元素个数我们用len()函数来计算。这就和swift或很多语言不一样了,比如在swift中, 我们计算数组元素个数,直接使用count来获取它的元素个数

print(names.count)

列表访问元素是和swift一样的,直接使用下标的方式

>>> names = ['Jhon', 'Alice', 'Bob', 'langke', '1', '2', '3']
>>> names[0]
'Jhon'
>>> names[2]
'Bob'

列表修改数组的元素

>>> fruits = ['apple', 'pear', 'banana']
>>> print(fruits)
['apple', 'pear', 'banana']
>>> fruits[1] = 'orange'
>>> print(fruits)
['apple', 'orange', 'banana']

列表添加元素

>>> ages = [18, 28, 38]
>>> print(ages)
[18, 28, 38]
>>> ages.append(48)
>>> print(ages)
[18, 28, 38, 48]

列表插入元素

>>> characters = ['a', 'b', 'c']
>>> print(characters)
['a', 'b', 'c']
>>> characters.insert(1, 'x')
>>> print(characters)
['a', 'x', 'b', 'c']

列表删除最后一个元素

>>> numbers = [11, 22, 33]
>>> print(numbers)
[11, 22, 33]
>>> numbers.pop()
33
>>> print(numbers)
[11, 22]

列表删除指定位置的元素

>>> numbers = [11, 22, 33]
>>> print(numbers)
[11, 22, 33]
>>> numbers.pop(1)
22
>>> print(numbers)
[11, 33]

列表还可以通过下面这种方式访问

>>> numbers = [11, 22, 33]
>>> numbers[-1]
33
>>> numbers[-2]
22
>>> numbers[-3]
11

下标-1表示倒数第一个元素下标, 下标-2表示倒数第二个元素下标, 下标-3表示倒数第三个元素下标, 以此类推...

Python的tuple

tuple也就是元组,也是一种有序列表, 在swift中也是这样的叫法。Objective-C就没有这个API。元组在很多时候很有作用,因为元组一旦创建,既有不可变性, 也就是你不能再去修改它。

既然元组不能改变,那么就以为着添加、删除、插入等改变元组的操作都不是允许的。

其他地方,元组和列表非常类似:

>>> names = ("Bob", "Alice", "Jhon", "Frank")
>>> len(names)
4
>>> print("this is a tuple: ", names)
this is a tuple:  ('Bob', 'Alice', 'Jhon', 'Frank')

但是,尤其需要注意的一点是,元组在定义一个元素的时候,需要在第一个元素后面加一个,, 比如

>>> age = (18,)
>>> len(age)
1

最后,针对tuple,我们来看一下一个比较有意思的事情。

既然说元组一旦创建就不能改变,也不会改变

在一个.py源文件中,我们有这样的代码

list = ['a', 'b']
names = ('Alice', 'Frank', list)
list[0] = 'x'
list[1] = 'y'
print(names)

或者

list = ['a', 'b']
names = ('Alice', 'Frank', list)
names[4][0] = 'x'
names[4][1] = 'y'
print(names)

然后执行该源文件

➜  Desktop python3 tuple.py
('Alice', 'Frank', ['x', 'y'])

咦?元组names怎么改变了呢?

事实上,元组的不会变是指指针的指向不会改变, 在上面的例子中,元组的最后一个元素也就是数组list是可以改变的,当我们改变list中的元素时,指向listnames的内容也就发生了改变,但是**指向并没有改变。

然而,如果我们这样做改变时

list = ['a', 'b']
names = ('Alice', 'Frank', list)
list = ['x', 'y']
print(names)

结果还是('Alice', 'Frank', ['x', 'y'])吗?

为了验证一下,我们来做个测试

➜  Desktop python3 tuple.py
('Alice', 'Frank', ['a', 'b'])

嗯?What's up??? 刚才不是说改变元组中的数组元素时,元组内容也会改变吗?那现在为何没有改变?

是这样的,由于数组list是一个变量,当我们做list = ['x', 'y']操作的时候,这就相等于在计算机在内存中开辟了另一块内存,并且是连续的内存,而之前的list = ['a', 'b']由于还有着元组names的指向,所以没有在内存中被销毁释放,所以names指向的是原来的数组list, 而不是新开辟的另一个"list"

那之前的改变和刚才的不一样?

是的,之前通过list[0] = 'x'的方式,你改变了数组的元素, 但是并没有开辟一块新的内存,也就是说,内存中只有一个list数组,只是元素发生改变而已。而list = ['x', 'y']本质是就是重新申请了一块内存空间,我们可以看做是内存中有"两个"list数组。

你可能感兴趣的:((四)Python的字符串,列表和元组)