前言
每一种语言都有其特定的数据类型,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
居中,而Python的str
在计算机的内存中又是以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字母的前缀的单引号或双引号来表示。
注意:编码的时候,如果是纯英文编码,要使用
ascii
或utf-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
list
在Python中叫列表, 其实,我们完全可以称之为数组, 和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
中的元素时,指向list
的names
的内容也就发生了改变,但是**指向并没有改变。
然而,如果我们这样做改变时
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
数组。