# 数据类型
# 内置类型
- Python 提供了 int、str 等基本数据类型。每种数据类型(或者说数据结构),实际上由某个内置 class 定义。
- 例:
>>> type(1) <class 'int'> >>> int # 在 C 语言中,int 是一个关键字。而在 Python 中,int 是一个 class 类名 <class 'int'>
- 调用某种数据类型的类名,可以创建这种数据类型的对象:
>>> int() 0 >>> str() ''
- 调用某种数据类型的类名,并输入一个值,可以将值转换成这种数据类型:
>>> int('1') 1 >>> str(1) '1'
- 例:
- 用户也可以自己创建 class ,自定义一些数据类型,比如三角函数。
# 不可变类型
Python 的以下数据类型,属于可变类型,允许读取、修改:
list set dict
它们的共同特点:
- 可以增加元素,也可以移除元素。
- 可以调用 clear() 方法,删除所有元素。
Python 的以下数据类型,属于不可变类型,只允许读取,不允许修改:
int float complex tuple str bytes
- 例:
>>> a = 'hello' >>> a[0] = 'H' # str 对象属于不可变类型,修改它会导致报错 TypeError: 'str' object does not support item assignment >>> a = 'world' # 这并不是修改 str 对象 ,而是让变量 a 指向另一个对象 >>> a = a + '!' # 这并不是修改 str 对象,而是拼接两个字符串,生成一个新 str 对象
- tuple 属于不可变类型,每个索引相当于一个 Python 变量,只能指向固定某个对象,不能换成其它对象。但如果该对象属于可变类型,则可以被修改。
>>> a = (1, 2, []) >>> a[2] = [3] # 不能改变某个索引指向的对象 TypeError: 'tuple' object does not support item assignment >>> a[2].append(3) # 可以修改该对象本身 >>> a (1, 2, [3])
- 例:
# bool
bool 类型的对象,只有
True
和False
两种取值(首字母必须大写),用于在逻辑判断中表示真、假。- bool 汉语译为"布尔"。
在 Python 解释器的底层,所有对象都以二进制的形式存储。其中,True 被存储为数字 1 ,False 被存储为数字 0 。
- 因此,bool 值,可以与数字混合运算:
>>> True - 1 0 >>> True + 1 2 >>> True + False 1 >>> True > False True
- 因此,bool 值,可以与数字混合运算:
通过
bool(<object>)
可以将任意类型的对象,转换成 bool 值。- 大部分对象,会被转换成 True 。
>>> bool(-1) # -1 虽然为负数,但取值不为空,因此被视作 True True >>> bool('0') # '0' 是一个 str 类型对象,Python 不管这个字符串的内容是什么,只要字符串的长度大于 0 ,则视作 True True >>> bool('False') True
- 以下对象,会被转换成 False 。
>>> bool(1 > 2) # 结果为假的逻辑表达式 False >>> bool(None), bool(''), bool(()), bool([]), bool({}) # 取值为空的基本数据类型对象 (False, False, False, False, False) >>> bool(0), bool(0.0), bool(-0), bool(-0.0) # 正数 0 和负数 0 (False, False, False, False)
- 大部分对象,会被转换成 True 。
# 数字
# int
int 类型的对象,用于存储整数。
- int 是英文单词 integer 的缩写,汉语译为"整数"、"整型"。
- 例:
>>> type(1) <class 'int'>
当用户输入一个整数常量时,默认会被 Python 解释器视作十进制数字。
- 也可以给数字添加以下前缀,声明为其它进制:
0b # 二进制 0o # 八进制 0x # 十六进制
- 例:
>>> 10 # 整型常量,默认被视作十进制 10 >>> 01 # 十进制数字,不能以 0 开头 File "<stdin>", line 1 01 ^ SyntaxError: leading zeros in decimal integer literals are not permitted; use an 0o prefix for octal integers >>> 0b10 # 将一个数字,声明为二进制。会被 Python 解释器自动转换成十进制,然后存储成 int 型对象 2 # 打印时,依然采用十进制的形式 >>> 0o10 8 >>> 0x10 16
- 也可以给数字添加以下前缀,声明为其它进制:
从其它进制转换成十进制:
>>> int('10', base=8) # 从 base 进制(str 类型),转换成十进制(int 类型)。base 默认为 10 8 >>> int('FF', base=16) 255 >>> int('0xFF', base=16) # 可以添加 0x 等进制前缀 255
从十进制转换成其它进制:
>>> bin(255) # 从十进制(int 类型)转换成二进制(str 类型) '0b11111111'
>>> oct(8) # 从十进制(int 类型)转换成八进制(str 类型) '0o10'
>>> hex(16) # 从十进制(int 类型)转换成十六进制(str 类型) '0x10' >>> '{:02x}'.format(16) # 也可以用 str.format() 方法转换,这样没有 0x 前缀 '10'
# float
C 语言中,设计了 double、float 两种浮点数(即包含小数的数字)。而 Python 中,只设计了 float 这种浮点数。
- 例:
>>> type(3.14) <class 'float'>
- float 类型至少会保留一位小数,因此与 int 类型看起来明显不同:
>>> 0.000 0.0
- float 默认最多保留 16 位小数,因此不能保存很长的小数:
>>> 5/3 # 5/3 的结果是一个无限循环小数,但 Python 只能保留有限长度的小数部分 1.6666666666666667 >>> round(5/3, 3) # 用 round() 函数,可以四舍五入,只保留指定长度的小数部分 0.333 >>> format(5/3, '.3f') # 将 float 值打印成字符串时,可以只保留 n 位小数 '1.667' >>> format(5/3, '.20f') # 如果打印超过 16 位的小数,则从第 17 位开始误差很大,没用 '1.66666666666666674068'
- 例:
float 类型的常量,可以用字母 e 声明为科学计数法。
>>> 1.2e+3 1200.0 >>> 1.2e-3 0.0012
几个特殊的浮点数:
>>> float('+inf') # 正无穷大 inf >>> float('-inf') # 负无穷大 -inf >>> float('nan') # 非数字 nan
# complex
complex
类型的对象,用于存储复数。- 复数的实部、虚部都是 float 浮点数。
- 复数的虚部,加上字母 j 后缀。
- 例:
>>> 2j 2j >>> 1+2j (1+2j) >>> complex(1, 2) # 用 complex() 创建一个复数 (1+2j) >>> complex(1) # 没有输入虚部时,默认值为 0j (1+0j)
# 序列
Python 中,list、tuple、str、bytes 等类型,都属于序列(sequence)。因为它们都会按顺序存放一组元素。
- list、tuple 中,每个元素,可以是任意类型的对象。
- str 中,每个元素,是一个字符。
- bytes 中,每个元素,是一个十六进制值。
序列类型的对象,具有以下特点:
- 每个元素有一个不同的序号,又称为索引(index)。
- 索引从 0 开始递增。第一个元素的索引为 0 ,第二个元素的索引为 1 ,以此类推,第 n 个元素的索引为 n-1 。
- 可用索引的语法。
- 可用切片的语法。
- 可用加号
+
拼接两个序列。例:>>> [1, 2, 3] + [4, 5, 6] [1, 2, 3, 4, 5, 6] >>> [1, 2, 3] + 'hello' # 不同数据类型之间,不支持拼接 TypeError: can only concatenate list (not "str") to list >>> {1} + {2} # set 类型不属于序列,不支持用加号拼接 TypeError: unsupported operand type(s) for +: 'set' and 'set' >>> dict() + dict() # dict 类型不属于序列,不支持用加号拼接 TypeError: unsupported operand type(s) for +: 'dict' and 'dict'
- 可用乘号
*
将一个序列复制几份,然后拼接在一起。例:>>> [1, 2, 3] * 2 [1, 2, 3, 1, 2, 3] >>> 'hello' * 2 'hellohello'
- 每个元素有一个不同的序号,又称为索引(index)。
# 索引
可用
sequence[下标]
的语法,获取序列中的一个元素(要求它的序号与下标匹配)。- 例:
>>> a = [1, 2, 3] >>> a[0] # 下标为 0 ,指向第一个元素 1 >>> a[-0] # [-0] 的效果相当于 [0] 1
- 下标可以为负数,表示倒序索引,
[-n]
指向倒数第 n 个元素。>>> a[-1] 3 >>> a[-2] 2
- 下标不能超过序列的长度,即超过
len(sequence)
,否则会抛出异常。因此,下标的有效取值范围为>>> a[3] IndexError: list index out of range >>> a[-4] IndexError: list index out of range
-len ≤ 下标 ≤ len-1
。
- 例:
上例中,通过下标获取一个元素之后,只是读取该元素的值。下面考虑修改的情况。
- 如果序列为 tuple、str、bytes 类型,则属于不可变类型,不允许修改元素。
>>> a = (1, 2, 3) >>> a[0] = 0 TypeError: 'tuple' object does not support item assignment
- 如果序列为 list 类型,则可以给该元素赋值:还可以用关键字 del 进行删除:
>>> a = [1, 2, 3] >>> a[0] = 0 >>> a # 可见 list 被修改了 [0, 2, 3]
>>> del a[0] >>> a [2, 3]
- 如果序列为 tuple、str、bytes 类型,则属于不可变类型,不允许修改元素。
# 切片
可用
sequence[start:stop:step]
的语法,获取序列中start ≤ index < stop
范围内的一连串元素,称为一个切片(slice)。- 这三种下标都有默认值,可以不填。
- start 默认值为 0 。
- stop 默认值为 len(sequence) 。
- step 默认值为 1 。
- 例:
>>> a = [1, 2, 3] >>> a[:] [1, 2, 3] >>> a[0:] [1, 2, 3] >>> a[0:0] # 这是获取 0 ≤ index < 0 范围内的元素,但不存在这样的元素,因此返回一个空的 list [] >>> a[0:1] [1] >>> a[0:2] [1, 2] >>> a[0:-1] # 输入的下标,可以为负数 [1, 2]
- 这三种下标都有默认值,可以不填。
切片中,下标可以填入任意 int 数字,不会引发异常。
- stop 可以超过序列的长度:
>>> a = [1, 2, 3] >>> a[0:9] # 这是获取 0 ≤ index < 9 范围内的元素 [1, 2, 3]
- start 可以大于 stop:
>>> a[9:0] # 这是获取 9 ≤ index < 0 范围内的元素,但不存在这样的元素,因此返回一个空的 list []
- stop 可以超过序列的长度:
step 称为步进值。作用是:从 start 这个元素开始,每隔 step 个元素,获取一个元素。
- 例:
>>> a = [1, 2, 3, 4, 5] >>> a[::2] [1, 3, 5] >>> a[1::2] [2, 4]
- step 可以为负数,表示从右往左,倒序获取元素。
>>> a[::-1] [5, 4, 3, 2, 1] >>> a[::-2] [5, 3, 1]
- 例:
如果序列为 list 类型,则可以给切片赋值:
>>> a = [1, 2, 3, 4, 5] >>> a[0:2] [1, 2] >>> a[0:2] = [0] # 赋值时,元素个数不必一致 >>> a # 可见 list 被修改了 [0, 3, 4, 5]
还可以用关键字 del 进行删除:
>>> del a[0:2] >>> a [4, 5] >>> del a[:] # 这是删除所有元素 >>> a [] >>> a[0:2] = [] # 赋值为空时,相当于删除这部分元素
可以将切片保存为一个 slice 对象,然后赋值给一个名称有意义的变量,从而提升代码的可读性。
>>> slice(0, 1) slice(0, 1, None) >>> first_element = _ >>> a = [1, 2, 3, 4, 5] >>> a[first_element] [1]
# list
# tuple
tuple 类型,与 list 类似,也是有序地存放一组元素。
- tuple 汉语译为"元组"。
对比 list 与 tuple 类型:
- tuple 只允许读,不允许修改。
- tuple 只能调用
tuple.count()
等少量方法。不支持 list 的大部分方法,因为 tuple 是只读的。
如何创建一个 tuple 对象?
- 可以调用
tuple()
,用法与list()
差不多。- 例:
>>> tuple() # 输入参数为空时,会创建一个空的 tuple 对象,不包含任何元素 [] >>> tuple('hello') # 输入一个可迭代对象时,会遍历其中的元素,组成一个 tuple 对象 ('h', 'e', 'l', 'l', 'o')
- 例:
- 用户可以输入一组元素,用英文逗号分隔,用圆括号
( )
作为定界符。此时 Python 解释器会将它保存为 tuple 对象。- 例:
>>> (1, 2, 3) (1, 2, 3) >>> type(_) <class 'tuple'>
- 如果用户输入一组元素,用英文逗号分隔,但没有加定界符。此时 Python 解释器会将它保存为 tuple 对象,而不是 list 对象。
>>> 1, 2, 3 (1, 2, 3)
- 如果 tuple 只包含一个元素,则必须加上逗号,强调为 tuple 类型。
>>> () # 这是一个空 tuple () >>> (1) # 这个 tuple 只包含一个元素,此时 Python 解释器会自动省略两侧的圆括号 1 >>> (1,) # 加上逗号,强调为 tuple 类型 (1,)
- 例:
- 对于 list ,Python 提供了列表推导式的语法,但对于 tuple ,没有元组推导式的语法。
- 如果将列表推导式的定界符改为圆括号
( )
,则会创建一个生成器,而不是一个元组。>>> (i for i in range(3)) <generator object <genexpr> at 0x0000029780FE8EB0> >>> tuple(_) # 可以手动将生成器,转换成 tuple 类型 (0, 1, 2)
- 如果将列表推导式的定界符改为圆括号
- 可以调用
# str
# bytes
bytes 表示字节类型,用于存储一段二进制数据,或者说 n 个字节的数据。
- bytes 与 str 类似,兼容 str 的大部分方法。
- str 以 Unicode 字符为单位,存储数据。
- bytes 以 byte 字节为单位,存储数据。
在 Python 解释器的底层,所有对象都以二进制的形式存储。当用户处理这些二进制数据时,就需要使用 bytes 类型的对象。
- 例如一个字符串 str ,是存储为一段二进制数据。
- 例如一个图片文件,是存储为一段二进制数据。
- 例如一个 mp3 文件,是存储为一段二进制数据。
如何创建一个 bytes 对象?
- 可以调用
bytes()
。>>> bytes() # 输入参数为空时,是创建一个长度为 0 的 bytes 对象 b'' >>> bytes(5) # 输入整数,会创建一个指定长度的 bytes 对象,由空字节组成 b'\x00\x00\x00\x00\x00'
- 可以给一个字符串,添加
b
前缀,将它声明为 bytes 对象。>>> b'Hello' b'Hello' >>> type(_) <class 'bytes'>
- 可以调用
str.encode()
,将 str 对象转换成 bytes 对象:>>> 'Hello'.encode() b'Hello'
- 可以调用
对 bytes 对象的索引:
>>> b ='你好'.encode('gbk') >>> b b'\xc4\xe3\xba\xc3' >>> b[0] # 索引 bytes 对象中的某个 byte 时,会自动将这个 byte 从十六进制,转换成十进制数 196 >>> hex(b[0]) '0xc4' >>> b[0:1] # 索引 bytes 对象中的一个切片时,会返回一个新的 bytes 对象 b'\xc4'
# bytearray
- bytearray 相当于将 bytes 以 list 的形式存储,允许修改。
- 例:创建 bytearray
>>> bytearray(3) # 可以输入一个数字,这会创建一个指定长度的 bytearray bytearray(b'\x00\x00\x00') >>> bytearray('hello') # 不能输入 str 类型的对象 TypeError: string argument without an encoding >>> bytearray('hello'.encode()) # 可以输入 bytes 类型的对象,这会转换成 bytearray 类型 bytearray(b'hello')
- 例:修改 bytearray
>>> b = bytearray('hello'.encode()) >>> del b[0] >>> b bytearray(b'ello')
- 例:创建 bytearray
# 哈希表
- 在 Python 底层,
- list 类型的对象,存放所有元素时,采用的数据结构为数组。
- 查找、附加一个元素时,时间复杂度为 O(1) 。
list.pop()
、list.append()
的时间复杂度为 O(n) 。因为每删除、插入一个元素,都要移动后面所有元素的位置,改变它们的索引。
- set、dict 类型的对象,存放所有元素时,采用的数据结构为哈希表。根据每个元素的哈希值,确定该元素的存储地址。
- 查找、删除、插入一个元素,时间复杂度为 O(1) ,效率高。
- 为了保证每个元素能计算出哈希值,set 要求每个元素属于不可变类型,dict 要求每个元素的 key 属于不可变类型。
- 为了保证每个元素能计算出不同的哈希值,set 要求每个元素不能重复,dict 要求每个元素的 key 不能重复。
- list 类型的对象,存放所有元素时,采用的数据结构为数组。
# set
# dict
# 特殊值
# None
None
在 Python 中是一个特殊的值,表示取值为空。>>> None # 在 Python 终端,如果一行代码的返回值为 None ,则不会显示该值 >>> print(None) # 如果主动用 print() 函数打印,则会显示 None 值 None >>> type(None) # 属于 NoneType 类型 <class 'NoneType'> >>> None == 0 # 空值并不等于 0 False
# pass
pass
在 Python 中是一个关键字,表示不执行任何操作。- Python 要求每个语句块至少包含一行代码。因此如果一个语句块的内容为空,可用
pass
填补空缺。 - 例:
>>> def fun1(): ... pass ... >>> fun1()
- Python 要求每个语句块至少包含一行代码。因此如果一个语句块的内容为空,可用
省略号
...
在 Python 中是一个从 ellipsis 类创建的单例对象,表示省略一处内容。- 例:
>>> ... Ellipsis >>> type(...) <class 'ellipsis'> >>> bool(...) # 它的布尔值为 True True
...
可以像 pass 一样,填补空缺的语句块。>>> def fun1(): ... ... ... >>> fun1()
...
可用于赋值。>>> a = ... >>> a = pass # pass 是一个关键字,不能用于赋值 SyntaxError: invalid syntax
- 当对象中的某个元素是对自身的循环引用时,会显示为
...
。>>> a = [1, 2, 3] >>> a.append(a) >>> a [1, 2, 3, [...]] >>> a[3] [1, 2, 3, [...]] >>> a[3][3] # 列表 a 循环引用自己,形成了无限循环 [1, 2, 3, [...]]
- 为了避免循环引用,应该避免引用传递,改用值传递:
>>> a = [1, 2, 3] >>> a.append(a.copy()) # 通过浅拷贝,实现值传递 >>> a [1, 2, 3, [1, 2, 3]]
>>> a = [1, 2, 3] >>> a = a + [a] # 这也属于值传递 >>> a [1, 2, 3, [1, 2, 3]]
- 例: