数据与变量
数据是所有编程语言的核心,程序的本质是将一些数据(输入)转换成另一些数据(输出)。在 Python 中,数据至关重要,数据处理、机器学习等高度依赖数据的任务是 Python 的主要应用领域。
在语句 print("Hello, World!") 中,"Hello, World!" 就是一个数据。
Python 常用的数据类型
数据通常被划分为不同的类型,因为不同类型的数据需要不同的处理方式。例如,数值数据可以进行加减乘除运算;字符串则更多用于截取、拼接等操作。下文列出了 Python 中最常用的数据类型。在这里,只需要对它们有个大致印象,后续章节会详细解释这些数据类型的使用方法。
-
数值型:
- 整型(int): 代表整数,例如:1, 100, -33。
- 浮点型(float): 代表实数,例如:3.14, -0.001。
- 复数型(complex): 代表复数,例如:3 + 4j。
-
布尔型(bool): 只有两个值:True 和 False。通常用于条件测试。
-
序列类型:
-
集合类型:
- 集合(set): 一个无序不重复元素集,基本功能包括关系测试和消除重复元素。例如:
{1, 2, 3}。 - 冻结集合(frozenset): 与集合类似,但是它是不可变的 。
- 集合(set): 一个无序不重复元素集,基本功能包括关系测试和消除重复元素。例如:
-
映射类型:
- 字典(dict): 无序的键值对集合,且键必须是唯一的。例如:
{'name': 'John', 'age': 30}。
- 字典(dict): 无序的键值对集合,且键必须是唯一的。例如:
-
- NoneType:只有一个值 None。用于表示一个值的缺失或空。
-
二进制类型:
- 字节序列(bytes): 包含字节的不可变序列,例如:b'hello'。
- 字节数组(bytearray): 包含字节的可变序列。
- 内存视图(memoryview): 通过 memoryview 对象访问其他数据结构的内存。
-
文件对象: 用于文件操作,例如:读取或写入文件。
-
其他数据类型: 许多 Python 模块和库都对数据类型进行了扩展。在使用了这些模块的程序中,很可能会遇到其他数据类型,如
numpy库中定义的ndarray或pandas库中定义的DataFrame等。
后文将对这些类型数据的用法再做详解。在继续介绍数据前,我们先要介绍一下“变量”(Variable)。
变量
在编程语言里,通常不是直接使用原始数据本身,而是要给数据起个名字,程序中通过名字来使用数据。这些数据的名称,或者叫标签,这就是“变量”。变量使我们能方便地对数据进行标记、存储和操作。
初学者常把变量与 代数方程中的变量(如 )进行类比,二者确实都有“占位符”的作用。但需要注意的是,编程中的变量更像是一个容器或指针。x = x + 1 在数学中并不成立,但在编程中它表示“计算 x + 1 的结果,并将其重新赋值给 x”。
比如下面这个打印函数的参数直接使用了数据本身:
print(5 + 5 + 5 + 5 + 5)
如果我们想让程序改而打印 3 + 3 + 3 + 3 + 3 的结果呢?那就需要把程序中每个数据 5 都替换成 3,非常麻烦。但如果给数据起个名字,比如叫做 x:
x = 5
print(x + x + x + x + x)
同时,在函数使用数据时,可以使用数据的名字 x。程序运行的结果是一样的,但当我们再次需要打印 3 + 3 + 3 + 3 + 3 时,只要把 x 的值改为 3 即可,无须修改每一处数据。
以下是关于 Python 中变量的几个基本概念和特点:
声明和赋值
赋值语句
在 Python 中,不需要显式地声明变量或其类型。当为变量赋值时,Python 会自动创建变量。
变量的值可以是数值、字符串或任何其他类型的数据。
变量的名字是一种标识符,遵循标识符的定义规范。它必须是一串大小写英文字母、数字和下划线 _ 的组合,并且变量名不能以数字开头。比如,name_1 是一个合法的变量名,而 1_name 不是。
Python 的变量命名区分大小写,这意味着 Variable 和 variable 是两个不同的变量。习惯上,变量名中不应该包含任何大写字母,Variable 不是一个符合 Python 习惯的变量名。
变量名不能包含空格,但可使用下划线来分隔其中的单词。比如,is_student 是一个合法的变量名,但 is student 不是。
应当避免使用 Python 中已有特定用途的名称作为变量名。例如,print 是 Python 中打印函数的名字,就不适合再用作变量名了。
虽然在语法上我们可以用任何单词作为变量名称,但为每个变量赋予具有描述性、恰当的名称,对于程序是否易读、易懂至关重要。
作为对比,有些语言,比如 C 语言,变量必须预先声明,然后才可以使用;有些语言,比如 JavaScript 还有专门的关键字 “var” 来定义变量;还有一些语言,比如 PHP 要求每个变量的名字都必须以一个特殊字符 “$” 开头。与这些语言相比,Python 对于变量的限制是最宽松的了。
下面的程序创建了一个数值为 5 的变量:
x = 5 # 创建一个名为 x 的整数变量,并赋值 5
上面这段程序,x 是变量名,5 是数据。等号 = 表示赋值操作,运行这段程序后,就会得到一个值为 5 的变量。这种为变量设值的操作被称为赋值语句。井号 # 表示注释,在程序中,井号后面的文字都只是说明文字,不参与程序运行。
类型提示
创建变量的时候,也可以为其添加类型提示(Type Hints),比如:
name: str = "谷货载"
age: int = 30
height: float = 5.9
is_student: bool = False
上面程序,变量名之后跟了一个冒号,冒号后面的文字指明了变量的数据类型。大多数编程语言,一旦指定了变量的数据类型,编译器或解释器就会自动检查变量的数据类型是否正确,如果有错误会报错。但是 Python 并不会施加任何真正的数据类型限制,这些类型提示仅仅是提示了预期的变量类型。运行下面的程序,Python 不会报告任何错误提示:
age: int = "Qizhen Ruan"
虽然 Python 自身不会在运行时检查变量的数据类型,但是类型提示对于代码的可读性非常有帮助。很多代码检查工具(如 mypy)也依赖于类型定义对代码进行类型检查。在 Pythora 星球上,程序中的变量通常都带有类型提示。
多变量赋值
Python 可以使用一个等号为多个变量赋值,变量名和变量名之间,数据 and 数据之间用逗号分隔。这在很多时候可以简化程序,比如说,在定义二维平面上位置的时候,总是需要一个 X 轴数据和一个 Y 轴数据,这两个数据可以同时定义:
x, y = 3, 5
lat, lon = 33.4, 77.98
一个常用的操作是把两个变量中的数据进行交换,多数语言都需要引入一个临时变量来解决这样的问题,但在 Python 中,这个操作可以更简洁:
x, y = 3, 5
x, y = y, x # x 和 y 中的数据被交换了,现在 x == 5, y == 3
如果给单个变量赋值多个数据,Python 会自动将所有数据打包成一个元组:
z = 3, 5
print(z) # 输出: (3, 5)
如果多个变量的值相同,也可以使用链式赋值,比如:
x = y = z = 4
上面的代码就相当于下面这三行代码:
x = 4
y = x
z = y
请读者分析一下下面这个程序的输出是什么:
x, y = y, x = z = 3, 5
print(x, y, z)
此代码涉及多重赋值,输出可能出乎意料,应谨慎使用。
链式赋值一般用于不可变数据类型(下文会详细解释)。链式赋值会导致所有变量都指向同一个数据,如果该数据是可变的,一旦其中一个变量修改了数据,其他所有指向该数据的变量的值也会随之改变,这可能会引发一些意想不到的问题。
动态类型
Python 是动态类型的语言。这意味着可以在程序运行时更改变量的类型。与之对比,多数语言中,变量的数据类型都是固定的,一旦声明,就不能再改变了。
x = 5 # x 是整数
x = "hi" # 现在 x 是字符串
动态数据类型的优点是简洁灵活,非常适合编写小型、临时使用的程序。许多编程语言最初为开发小型程序设计,因此倾向于采用动态类型。其中一些语言后来的应用场景已经远远超出了最初的设计,用其开发的程序规模越来越大。然而在大型程序中,动态数据类型带来的麻烦却远超过其优点。比如,它会导致无法在程序运行前检查数据类型错误、降低代码可读性、影响运行效率,并难以优化。所以,很多语言,如 JavaScript 和 PHP,后来都演化出了支持静态类型或禁用动态类型的超集/版本(如 TypeScript),以便更好地支持大型程序开发。
变量的“变”
解释程序的时候,我们经常会说:“把变量 x 中的数据变成 5”之类的话。但是这样的说法非常不严谨,它没有说清楚:到底是把变量指向一个不同的数据;还是让变量仍然指向同一个数据,但是改变这个数据的值。
在 Python 中,使用赋值语句,改变的一定是变量的指向。比如,我们先让 x = 5,然后再让 x = 3,那么这时候,一定是 x 指向了不同的数据,而不是原来那个数据从 5 变成了 3。
x = 5 # x 指向 5
x = 3 # 现在 x 指向了另一个数据
不同的变量是可以指向同一个数据的,如果赋值语句的两边分别是两个变量,那么就表示左边的变量将也指向右边变量指向的数据。
x = [1,2] # x 指 向 [1,2]
y = [1,2] # x 和 y 指向了不同的数据,但是他们的值都是 [1,2]
x = [1,2] # x 指向 [1,2]
y = x # y 也指向了 x 指向的那个数据