Python数据介绍
2.1.1. 数据类型
- 数值类型
² 整数类型(int)
² 浮点类型(float)
² 复数类型(complex)
- 布尔类型
- 序列类型
² 列表(list)
² 元组(tuple)
² 字符串(str)
² 字节(bytes)
- 映射类型(dict)
- 集合类型(set)
- 其他内置类型
鸭子类型
在Python中,严格来说,变量是不具有类型的,变量的类型完全取决于其所关联的对象类型,这与其他语言的差别较大(C,Java等)。因此,我们常习惯的成Python的类型为“鸭子类型”,这是一种动态类型的体现。
说明:
- 由于变量必须要关联一个具体的对象,才能确定变量的类型。因此,在定义变量时,不能只给出变量的名字,必须要同时也给出变量所关联的对象。
- Python2中还支持长整数类型(long),在Python3中取消。
2.1.2. 整数类型
# 整数类型,类似于数学上的整数。
# 整数类型支持四种进制表示。
# 1 二进制 使用0b或0B前缀
# 2 八进制 使用0o或0O前缀
# 3 十进制 无前缀
# 4 十六进制 使用0x或0X前缀。对于10 ~ 15之间的数值,使用字母a(A)~ f(F)来进行表示。
# 十进制
x = 10
print(x)
# 二进制
x = 0b10101
print(x)
# 八进制
x = 0o777
print(x)
# 十六进制
x = 0x1e78
print(x)
整数类型(int)是最常使用的类型。我们数学上使用的整数,例如,3,-50等,这些都是整数类型。
四种进制表示
整数类型支持四种进制表示:
- 二进制(使用0b或0B前缀)
- 八进制(使用0o或0O前缀)
- 十进制(无前缀)
- 十六进制(使用0x或0X前缀,10 ~ 15使用a ~ f或A ~ F表示)
进制转换
# 进制转换
# bin 转换成二进制
# oct 转换成八进制
# hex 转换成十六进制
x = 888
print(bin(x))
r = bin(x)
# 错误,str与int不能进行加法运算。
# print(r + 1)
# 可以使用type函数获取数据的类型。输出是str类型 <class 'str'>
print(type(bin(x)))
print(oct(x))
print(hex(x))
# print(int(0b1010))
# print(0b10101)
print(int("100"))
print(int("100", 10))
# int函数在进行转换时,可以指定进制。默认为十进制。
print(int("100", 2))
print(int("100", 2))
print(int("100", 3))
# 当数值较大时,我们可以在数值之间加入_来分隔,进而提高程序的可读性。
big_number = 1287_2358
我们可以调用相应的函数,来对四种进制之间进行转换。
- bin其他进制转换为二进制
- oct其他进制转换为八进制
- int其他进制转换为十进制
- hex其他进制转换为十六进制
分隔符_
当数值较大时(尤其是二进制),对程序的可读性会造成影响,此时,我们可以在数值之间使用一个_进行分隔,从而提高程序的可读性(Python3.6)。
2.1.3. 布尔类型
# 布尔类型
# 布尔类型表示一种逻辑的判断,指条件成立或不成立。
# 布尔类型只有两个值,True与False。True表示真(成立),False表示假(不成立)。
t = True
f = False
# 布尔类型(bool)是整数类型(int)的子类型。
# True就是1,False就是0。
# 整数类型转换成布尔类型的原则:0为False,非0位True。
print(True == 1)
print(True == 2)
print(False == 0)
# 布尔类型也可以参与数学上的运算。因为布尔类型True就是1,False就是0。
# 但是,我们最好不要这样做。
print(True + 5)
布尔类型(bool)表示的是一种条件的判断,具有两个值:True与False。其中,True表示条件成立,即为“真”,而False表示条件不成立,即为“假”。
布尔类型是整数类型的子类型。实际上,True就是1,False就是0。因而,我们也可以使用布尔类型参与数学上的运算,与使用1与0参与运算的结果是一样的。
练习进制以及转换。
尝试确定int类型的取值范围。(最小值与最大值)
2.1.4. 浮点类型
# 浮点类型(float)就是数学上的小数类型。3.5,1.8。
# 浮点类型仅支持十进制。
f = 1.5
print(type(f))
f = True
print(type(f))
# 整数类型不能在前面加上0
#f = 03
# 浮点类型可以在前面加0。
f = 03.
# 浮点类型还支持科学计数法的表示。
# 使用e(E)表示以10为底。
# 1.5 * 10 ^ 10
f = 1.5e10
print(f)
# 浮点类型的大小(范围)与实现相关。通常使用C程序中的double类型来实现。
f = 1.2e308
print(f)
import sys
print(sys.float_info)
print(sys.float_info.max)
print(sys.float_info.min)
# float类型的特殊值 NaN Infinity, -Infinity。
print(float("NaN"))
print(float("Infinity"))
n = float("NaN")
# NaN是一个特殊的值,其不等于任何值,包括其自身。
print(n == n)
import math
# 因为NaN不等于任何值,所以,我们不能使用==进行判断,而是要使用math提供的函数isnan进行判断。
# isnan,如果参数是nan,则返回True,否则返回False。
print(math.isnan(n))
# 浮点类型仅是近似的存储,浮点类型是不精确的。
# 0.33333333333……
# 由于浮点类型的不精确性,我们在使用浮点类型时,需要注意:
# 1 避免数量级相差很大的两个浮点类型进行运算。
f1 = 5e20
f2 = 1
f1 = f1 + f2
print(f1)
# 2 避免进行等量的判断
f1 = 0.1
f2 = 0.2
print(f1 + f2)
print(f1 + f2 == 0.3)
print(0.1)
# / 输出为浮点数
x = float(input("请输入第一个数值:"))
y = float(input("请输入第二个数值:"))
print(x + y, x - y, x * y, x / y)
浮点类型(float)就是数学上的小数类型。例如:1.0,-2.5等,都是浮点类型。在进制表示上,浮点类型仅支持十进制表示(这点不同于整数类型)。除了常规的表示方式外,浮点类型也可以使用数学上科学计数法的形式表示,例如:
1.5e30
说明:
- 十进制的整数类型不能使用0开头,但是,浮点类型可以以0开头。
尝试确定float类型的取值范围。
浮点类型的特殊值
浮点类型具有两个特殊值:NaN(Not A Number)与Infinity(无穷大),其中无穷大又可分为正无穷(+Infinity)与负无穷(-Infinity)。我们可以通过float函数来获得这些值。
NaN有一个特征,就是自己不等于自己,因此,我们不能通过==来判断一个数值是不是NaN。
浮点类型的不精确性
在使用浮点类型时,我们需要留意,浮点类型在计算机中仅是近似的存储,浮点类型是不精确的。因此,我们要避免进行如下的操作:
- 避免数量级相差很大的浮点值之间进行运算。
- 避免进行等量的比较。
练习浮点类型的计算,自行找出还有哪些计算体现出不精确性。
Decimal的使用
# Decimal类型的使用。进行精确的浮点计算。
import decimal
'''
x = decimal.Decimal(0.1)
y = decimal.Decimal(0.2)
print(x)
print(y)
print(x + y)
#print(0.1)
#print(0.2)
x = decimal.Decimal("0.1")
y = decimal.Decimal("0.2")
print(x + y)
'''
# Decimal计算,默认为28位有效数字。我们可以进行修改。
# 获得decimal的计算上下文环境
context = decimal.getcontext()
# 对计算精度(有效数字)进行设置,默认为28。
context.prec = 3
x = decimal.Decimal(0.1)
y = decimal.Decimal(0.2)
print(x+y)
考虑到浮点类型的不精确性,因此,如果我们需要进行精确计算时,我们可以使用decimal模块中的Decimal类来实现,该类提供精确的浮点计算。
此外,我们也可以指定Decimal的计算精度,即计算结果最多保留的有效数字位数,默认为28位有效数字。
2.1.5. 复数类型
# 复数类型(complex) 分为实部与虚部,与数学上的复数相似。数学上使用i表示虚部。
# 在Python当中使用j或J表示虚部。
x = 3 + 5j
print(type(x))
print(x.real)
print(x.imag)
# 类型之间的转换
i = 5
f = 3.0
c = 10 - 3j
# int,float,complex可以混合运算。结果类型为参与运算操作数类型较高的一个。
# 类型从低-》高
# int -> float -> complex
print(type(i + f))
print(type(i + c))
print(type(f + c))
# 类型转换
# int, float, bool, complex
# 类型转换函数
# int()
# float()
# bool()
# complex()
i = 1
f = -2
b = True
c = 32 - 3j
# float类型转换成int类型,去掉小数点后面的内容。取整数部分。
print(int(f))
print(float(i))
# int,float转换成complex类型,虚部为0。
print(complex(i))
print(complex(f))
# complex不能转换成int与float类型。
# print(int(c))
# print(float(c))
# 在Python中,任何类型都能够转换成bool类型。
# 数值类型(int,float, complex),转换成bool类型,0为False,非0为True。
print(bool(20))
print(bool(0))
print(bool(20.0))
print(bool(0.0))
print(bool(0 + 0j))
print(bool(1 + 2j))
# True就是1,False就是0。
print(int(True))
print(int(False))
print(float(True))
print(float(False))
print(complex(True))
print(complex(False))
Python中的复数类型(complex)类似于数学上的复数。含有虚部(使用j或J后缀)的数值为复数类型。例如:3 + 5j,-2 - 3j(数学中虚部后缀为i)。复数分为实部与虚部两个部分,我们可以通过real与imag属性分别获取复数的实部与虚部的值。
2.2. 类型转换
获取数据类型
我们可以通过type函数获取变量的类型,准确的讲,应该是变量所关联的对象的类型。
使用int,float与complex进行混合运算,确定结果的类型,总结。
类型转换函数
我们可以在不同的类型之间进行类型转换,Python中为我们提供了如下的转换函数:
- int(value)
将数值类型或字符串转换为整数(int)类型。如果没有参数,返回0。
print(int(True))
- float(value)
将数值类型或字符串转换为浮点(float)类型。如果没有参数,返回0。
- complex(real, imag)
根据实部与虚部(可选)创建一个复数。如果没有参数,返回0j。
- bool(value)
参数为真值时,返回True,否则返回False。任何类型都可以转化为布尔类型
4种类型之间的转换
说明:
尽管可以使用转换函数进行类型转换,但并非任意两个类型之间都是能够进行转换的。例如,复数类型就不能够通过int或float转换为整数或浮点类型,可以转化为布尔类型
此外,int函数还可以提供第二个参数,指定解析转换时,使用的进制。此时,第一个参数需要是字符串类型(或字节等类型),不能是数值类型。例如:
int(“300”, 16)
则会根据16进制来解析300,最终函数返回的结果为768,而不是300。如果没有指定第二个参数,则默认为十进制。
2.3. 运算符
运算符,即具有特殊计算规则的符号。运算符涉及到的,参与运算的数据,称为操作数。不同的运算符,涉及的操作数也不相同。例如,加法运算符“+”涉及两个操作数,而负号运算符“-”则涉及一个操作数。运算符涉及几个操作数,我们就称该运算符是几元运算符,例如,加法运算符“+”为二元运算符,而负号运算符“-”为一元运算符。由运算符与操作数结合起来的计算式,称为“表达式”。
我们可以将运算符分为如下几类:
- 算术运算符
- 布尔运算符
- 比较运算符
- 位运算符
- 赋值运算符
2.3.1. 算术运算符
# 算术运算符
x = 10.0
y = 3
print(x + y)
print(x - y)
print(x * y)
print(x / y) 结果为浮点数
# 整除运算,但不意味着结果一定是int类型。
# 整除运算,结果向下取整。(向负无穷大方向取整)
print(x // y)
print(-10 // 3)
# 整除有两种原则:
# 1 向0取整
# 2 向下取整
# %
# 1 取余运算 向0取整
# 2 取模运算 向下取整
# 被除数 = 除数 * 商 + 余数
# 被除数 - 除数 * 商 = 余数
# 如果不能整除(余数不为0),对于取余运算,余数的符号与被除数相同。
# 对于取模运算,余数的符号与除数相同。
余符被除数 模符除数
print(x % y)
print(-10 % 3) # 商为-4(向下取整) -3 (向0取整)
print(2 ** 5)
# +号,通常可以省略。
print(+5)
# -号
print(-5)
# 进行除法运算,除数不能为0,否则会在运行时产生异常。
print(5 / 0)
算术运算符用来进行类似数学上的加减乘除运算。
符号 | 说明 |
x + y | 加法运算,返回x与y的和。 |
x – y | 减法运算,返回x与y的差。 |
x * y | 乘法运算,返回x与y的积。 |
x / y | 除法运算,返回x与y的商(浮点类型)。 |
x // y | 除法运算,返回x与y的商(向下取整)。 |
x % y | 取模运算,返回x模y的结果。 |
x ** y | 乘方运算,返回x的y次方。 |
+x | 正号,x的值不会改变,该符号可以省略。 |
-x | 负号,取x的相反数。 |
在除法运算时,除数不能为0,否则会产生错误(ZeroDivisionError)。
算术运算符的使用。注意取余与取模的差别。
2.3.2. 布尔运算符
# 布尔运算符
# and or not
# and,连接两个表达式,表示并且。仅当两个表达式的值都为True,整个表达式的值才为True,否则,
# 整个表达式的值为False。
x = 5 == 3 and 3 == 3
print(x)
# or,连接两个表达式,表示或者。只要两个表达式有一个为True,则整个表达式的值为True。否则,
# 整个表达式的值为False。
y = 5 == 3 or 3 == 4
print(y)
# not 对条件的一种否定。True -> False, False -> True
print(not True)
print(not 5 == 3)
# and与or表达式的类型未必一定是布尔类型,可以是任意类型。
# 因为Python中,任何类型都能够转换成布尔类型。
# and或or结果总是会返回两个表达式中的一个。
# 对于and,如果第一个表达式为False,则返回第一个表达式。如果第一个表达式为True,则返回第二个表达式。
# 对于or,如果第一个表达式为True,则返回第一个表达式。如果第一个表达式为False,则返回第二个表达式。
x = 3 and "abc"
print(x)
x = 0 and "abc"
print(x)
y = 3 or "abc"
print(y)
y = 0 or "abc"
print(y)
# and与or的短路。
# 当and的第一个表达式为False,或者or的第一个表达式为True,则此时就可以确定整个表达式的值,
# 第二个表达式会直接越过,不会得到执行。
# 证明and与or发生了短路。
x = 0 and print("不执行")
print(x)
x = 1 or print("不执行")
print(x)
布尔运算符也称逻辑运算符,列表如下:
符号 | 说明 |
x and y | 如果x为True,返回y,否则返回x。 |
x or y | 如果x为True,返回x,否则返回y。 |
not x | 如果x为True,返回False,否则返回True。 |
x与y未必一定是布尔类型(取值为True与False),实际上,x与y可以是任意类型,因为在Python中,任意类型都可以转换为布尔类型。and与or运算符总是会返回x与y二者中的一个。
短路
and与or运算符会执行短路操作。
证明and与or的短路现象。(提示:print函数)
2.3.3. 比较运算符
# 比较运算符
x = 1
y = 2
print(x > y)
print(x < y)
print(x >= y)
print(x <= y)
# 值的比较
print(x == y)
print(x != y)
# 同一性的比较
print(x is y)
print(x is not y)
# ==(!=)与is(is not)的比较区别:
# is 比较的是两个对象是否为同一个对象。是同一个对象,返回True,否则返回False。
# 而== 比较的是两个对象的值是否相等,是返回True,否则返回False。
# is 如果为True,则==必为True。
# == 如果为True,is未必为True。
import decimal
a = decimal.Decimal("0.1")
b = decimal.Decimal("0.1")
print(a == b) True
print(a is b) False
x = 3
# 1 <= x <= 5
# x >= 1 && x <= 5
# Python支持链式比较。
y = 1 <= x <= 5
# 相当于x >= 1 and x <= 5
# 链式比较也同样具有短路特征。
比较运算符执行的是比较运算,如果表达式成立,返回True,否则返回False。
表格 23 比较运算符
符号 | 说明 |
x > y | 如果x大于y,返回True,否则返回False。 |
x >= y | 如果x大于等于y,返回True,否则返回False。 |
x < y | 如果x小于y,返回True,否则返回False。 |
x <= y | 如果x小于等于y,返回True,否则返回False。 |
x == y | 如果x等于y,返回True,否则返回False。 |
x != y | 如果x不等于y,返回True,否则返回False。 |
x is y | 如果x与y是同一个对象,返回True,否则返回False。 |
x is not y | 如果x与y是不同的对象,返回True,否则返回False。 |
在Python语言中,比较运算符支持链式比较。x < y < z相当于x < y and y < z,不同之处仅在于,后者中y只会计算一次。链式比较与拆分成and或or连接的表达式一样,也会进行短路操作。
is与==,is not与!=的区别在于,==与!=比较的是对象内部的值是否相等,而is与is not比较的是两个对象是否为同一个对象。
2.3.4. 位运算符
# 位运算符。
# & 按位与运算。
# 每个对应位进行运算,如果两个位都是1,则结果为1,否则结果为0。
print(5 & 3)
# | 按位或运算
# 每个对应位进行运算,如果两个位都是0,则结果为0,否则结果为1。
print(5 | 3)
# ^ 异或运算
# 每个对应位进行运算,如果两个位相同,则结果为0,否则结果为1。
print(5 ^ 3)
# << 左移位运算 x << y
# 将x向左移动y所指定的位数。右侧以0进行填充。
print(15 << 1)
print(5 << 2)
# >> 右移位运算 x >> y
# 将x向右移动y所指定的位数。右侧以符号位进行填充。(正数填充0,负数填充1)
print(15 >> 1)
print(14 >> 1)
print(-15 >> 1)
# 左移一位相当于乘以2,右移一位相当于除以2(如果不能整除,则结果向下取整)。
# 原码 数值原本应该表示的形式。(我们容易理解接受的方式)
# 反码 符号位不变,其他所有位按位取反。(0变成1,1变成0)
# 补码 正数的原码与补码相同。负数的补码,在原码的基础上,按位取反,然后加1。(反码加1)。
# 计算机中,是以补码的形式进行存储的。
# 从原码转换成补码,与由补码转换成原码的方式相同。正数原码与补码一致,无需转换,
# 负数:按位取反,然后加1。
# ~ 按位取反运算,0变1,1变0。
print(~6)
# 赋值运算符
# x op= y op 可以是 + - * / // ** 等
# x op=y 相当于 x = x op y
x = 1
x += 10 # x = x + 10
print(x)
位运算符提供的是对位(bit)进行的操作。位运算符的操作数要求是整数类型(布尔类型)。位运算符如下表所示:
表格 24 位运算符
符号 | 说明 |
x & y | x与y按位与运算,如果两个位都是1,结果为1,否则结果为0(有0则结果为0)。 |
x | y | x与y按位或运算,如果两个位都是0,结果为0,否则结果为1(有1则结果为1)。 |
x ^ y | x与y按位异或运算,如果两个位相同,则结果为0,如果两个位不同,则结果为1(有1则为1,但又不同时为1)。 |
x << y | 将x向左移动y位,右侧以0进行填充。y不能为负值,否则会产生ValueError。 |
x >> y | 将x向右移动y位,左侧以符号位进行填充。y不能为负值,否则会产生ValueError。 |
~x | 对x进行按位取反,即1变为0,0变为1。 |
~翻转 x的翻转是-(x+1),即正数变负数,负数变正数
说明:
布尔类型作为整数类型的子类型,也可以参与位运算,但是,最好不要这样,因为布尔类型的作用是进行逻辑上的判断,而不是当成数值1与0参与数学运算。
2.3.5. 赋值运算符
赋值运算符包括简单赋值运算符与复合赋值运算符。
符号 | 说明 |
x = y | 简单赋值运算。即x关联y所关联的对象。 |
x op= y | 复合赋值运算。op可以是任意二元算术运算符与二元位运算符。 x op= y相当于x = x op y。例如x += y相当于x = x + y。 |
说明:
- x op= y与x = x op y并非完全等价,原因我们在后面说明。
2.4. 运算符优先级
在小学时,我们学习数学运算,就已经非常明确要先算乘方,然后乘除,然后加减。这里,先算与后算体现的就是一种计算的先后顺序,我们称这种计算顺序为运算符的优先级。同样,在Python中,运算符也存在着优先级的概念,如下表所示,优先级从高到低进行排列,同一行的运算符具有相同的优先级:
运算符优先级 |
. () [] |
** |
+(正号) -(负号) ~ |
* / // % |
+ - |
<< >> |
& |
^ |
| |
in not in is is not < <= > >= == != |
Not |
And |
Or |
= op=(+ - * / // % ** >> << & ^ |) |
初看之,运算符眼花缭乱,优先级层出不穷,难免会令初学者望而生畏。然而,在更多的时候,我们没有必要刻意去记忆优先级的顺序。当我们在使用表达式,无法确定优先级时,我们可以使用小括号()来调整表达式的结合性,小括号()的优先级是最高的(这点与数学上相同)。
说明:
- 上表中部分运算符需要用到后面的知识,故我们并没有在本章中提及,我们会在后续的章节中学习。
优先级说明
在Python中,运算符的优先级与数学上还是有一些差别的,在数学中,我们可以认为优先级高的会先计算,然而,在Python中,运算符优先级更多体现的是一种结合性,而不是计算的顺序。
例如,假设如下的表达式:
x + y * z
如果在数学中,我们可以认为是先计算y * z,然后再与x求和。但是在Python中却并非如此。首先*的优先级高于+,因此,表达式可以认为是按照如下的方式进行结合:
x + (y * z)
此时,Python解释器会首先计算x的值,然后计算y的值,再计算z的值,接下来计算y * z的值(假设为w),最后计算x与w的和。也就是说,x的计算会先于y与z,而不是我们按照数学思维所想象的——先计算y * z的乘积,然后再计算x,最后求和。
明确这种计算方式有什么意义吗?当然!我们可以想象一下,如果在计算x的时候,会改变后面y或者z的值,结局会是如何?此时,按照数学思维与按照Python(计算机)思维,就会得到不同的结果。