# 数据类型

2023年8月03日12分钟阅读

- FormalSciences/ComputerScience
- ProgrammingLanguage/Python
- Python/Basics

在编程领域，理解和掌握各种数据类型是任何编程语言的基础，Python 也不例外。Python 3 提供了多种内置数据类型，包括但不限于数字（整型、浮点型、复数）、布尔型、列表、元组、字符串、集合、字典等，还有函数、模块等高级类型。每种数据类型都有其特定的特性和适用场景。

> 在 Python 中，变量可以被理解为一个标签（tag）或者标记，它是附着在特定对象上的名字。你可以将这个理念理解为在超市里的商品标签，标签告诉你这是什么商品，而商品是具体的物品。同样的，Python 的变量名就像是一个标签，它告诉我们这个变量指向的是什么对象，而对象是存储在内存中的具体数据。

## 对象与类型

**在 Python 中，几乎所有的数据都可以被视为对象，每一个对象都有其相应的类型。**例如：

    print(type(123))  # <class 'int'>
    print(type(3.14))  # <class 'float'>
    print(type('hello'))  # <class 'str'>

**Python 是动态类型语言，我们不需要预先声明变量的类型。**在程序运行过程中，变量的类型可以根据赋值而改变。例如：

    x = 123  # x 是一个整数
    print(type(x))  # <class 'int'>

    x = 'hello'  # x 变成了一个字符串
    print(type(x))  # <class 'str'>

Python 中有两个内置函数 `id` 和 `type`。

- `id(obj)` 函数：返回对象 `obj` 的唯一标识符，其实质上是该对象在内存中的地址。
- `type(obj)` 函数：返回对象 `obj` 的类型。

### 引用计数和垃圾收集

Python 不依赖存储期（即对象在内存中存在的时间）来管理变量和对象，而是使用引用计数。每个对象都会计算有多少个变量引用了它，当引用计数为 0 时，对象就会被垃圾收集器删除。可以使用内置的 `id` 函数获取对象的标识（这实际上是该对象的内存地址），使用 `type` 函数获取对象的类型。

    # 引用计数和垃圾收集的例子：
    # 在代码中，`sys.getrefcount(a)`可以获得对象`a`的引用计数。
    # 当我们创建一个新的引用`b`时，`a`的引用计数增加1。
    # 当我们删除`b`时，`a`的引用计数减少1。

    import sys

    a = []  # 创建一个空列表

    print(sys.getrefcount(a))  # 输出：2，一个引用来自 a，一个来自 getrefcount 的参数

    b = a  # 增加一个引用

    print(sys.getrefcount(a))  # 输出：3，新增一个引用来自 b

    b = None  # 删除一个引用

    print(sys.getrefcount(a))  # 输出：2，b 不再引用

### 可变类型、不可变类型

Python 中的数据类型可以分为两大类：可变类型与不可变类型。

- 可变类型：值可以更改，如列表、字典和集合。
- 不可变类型：值不可更改，如数字、字符串、元组等。

不可变类型的变量如果改变值，实际上是生成了一个新的对象，并使变量引用新的对象。Python 的赋值语句复制的是对象的引用，而不是对象的值。因此，Python 中的“变量”与其他编程语言中的“变量”不完全相同，将其翻译为“引用”可能更加合适。

    # 在代码中，`list1`是一个列表，是可变类型。
    # 我们可以通过`append`方法修改`list1`，但是`list1`的`id`并未改变，说明`list1`还是同一个对象。
    # `x`是一个整数，是不可变类型。当我们改变`x`的值时，`x`的`id`改变了，说明`x`现在是一个新的对象。

    # 可变类型：列表
    list1 = [1, 2, 3]
    print(id(list1))  # 输出 list1 的 id
    list1.append(4)  # 修改 list1
    print(id(list1))  # id 没有改变

    # 不可变类型：整数
    x = 1
    print(id(x))  # 输出 x 的 id
    x = x + 1  # 修改 x
    print(id(x))  # id 改变了

## Python3 内置类型

Python 3 内置了多种数据类型，同时还内建了许多其他类型，如上下文管理器类型、模块、方法、代码对象、类型对象、内部对象等。

### 数字类型

数字类型主要用于存储和处理数值。这包括整数、浮点数、复数和布尔类型。

类型 | 描述 | 示例 | 可变性
--- | --- | --- | ---
int | 整数，无论大小都可以是正数或负数。 | `123`, `-456`, `0` | 不可变
float | 浮点数，包含小数部分的数字。 | `3.14`, `-0.01`, `9.0` | 不可变
complex | 复数，包含实部和虚部的数字。 | `1+2j`, `3-4j` | 不可变

### 布尔类型

类型 | 描述 | 示例 | 可变性
--- | --- | --- | ---
bool | 布尔，表示真或假的值。 | `True`, `False` | 不可变

### 序列类型

序列类型是一种有序的元素集合，包括字符串、列表和元组。每个元素都有一个相应的索引，可以通过索引来访问。

类型 | 描述 | 示例 | 可变性
--- | --- | --- | ---
str | 字符串，由零个或多个字符组成的文本。 | `'hello'`, `"world"`, `''` | 不可变
list | 列表，由一系列按特定顺序排列的元素组成。 | `[1, 'two', 3.0]` | 可变
tuple | 元组，类似于列表，但元素不可更改。 | `(1, 'two', 3.0)` | 不可变

### 集合类型

集合类型是一个无序的元素集合，其中的元素都是唯一的。这包括集合和冻结集合。

类型 | 描述 | 示例 | 可变性
--- | --- | --- | ---
set | 集合，一组无序的、不重复的元素。 | `{1, 'two', 3.0}` | 可变
frozenset | 不可变集合，类似于集合，但元素不可更改。 | `frozenset({1, 'two', 3.0})` | 不可变

### 映射类型

映射类型是一个存储键值对的元素集合，其中的键是唯一的。字典就是一个映射类型。

类型 | 描述 | 示例 | 可变性
--- | --- | --- | ---
dict | 字典，包含键值对的数据结构。 | `{'name': 'John', 'age': 25}` | 可变

### 特殊类型

类型 | 描述 | 示例 | 可变性
--- | --- | --- | ---
NoneType | 表示 None 的特殊类型。 | `None` | 不可变
EllipsisType | 表示省略的特殊类型，主要在切片和 NumPy 库中使用。 | `Ellipsis` 或 `...` | 不可变
NotImplementedType | 表示未实现方法的特殊类型，主要在自定义比较方法中使用。 | `NotImplemented` | 不可变

### 二进制类型

类型 | 描述 | 示例 | 可变性
--- | --- | --- | ---
bytes | 字节，包含零个或多个范围为 0⇐x<256 的整数的不可变序列。 | `b'hello'`, `b'\x01\x02'` | 不可变
bytearray | 字节数组，包含零个或多个范围为 0⇐x<256 的整数的可变序列。 | `bytearray(b'hello')` | 可变
memoryview | 内存查看，用于访问其他二进制序列、打包的数组和缓冲区的内部数据。 | `memoryview(b'hello')` | 依据所查看对象

### 类、实例和异常

类型 | 描述 | 示例 | 可变性
--- | --- | --- | ---
object | 对象，所有类的基类。 | `obj = object()` | 依据具体类
exception | 异常，程序运行时的错误。 | `raise Exception('Error!')` | 不可变

### 其他内置类型

类型 | 描述 | 示例 | 可变性
--- | --- | --- | ---
function | 函数，包含一系列指令的代码块。 | `def greet(): print('Hello!')` | 不可变
type | 类型，表示对象的类型。 | `type(123)` | 不可变
generator | 生成器，一种可迭代的对象，由函数定义并使用 `yield` 产生值。 | `(x**2 for x in range(10))` | 不可变

## 类型转换

Python 提供了多种函数，用于在不同类型之间进行转换：

    x = "123"  # 这是一个字符串
    print(type(x))  # <class 'str'>

    x = int(x)  # 将字符串转为整数
    print(type(x))  # <class 'int'>

    x = float(x)  # 将整数转为浮点数
    print(type(x))  # <class 'float'>

函数 | 描述
--- | ---
int(x [,base]) | 将 x 转换为一个整数
float(x) | 将 x 转换到一个浮点数
complex(real [,imag]) | 创建一个复数
str(x) | 将对象 x 转换为字符串
repr(x) | 将对象 x 转换为表达式字符串
eval(str) | 用来计算在字符串中的有效 Python 表达式,并返回一个对象
tuple(s) | 将序列 s 转换为一个元组
list(s) | 将序列 s 转换为一个列表
set(s) | 转换为可变集合
dict(d) | 创建一个字典。d 必须是一个 (key, value) 元组序列
frozenset(s) | 转换为不可变集合
chr(x) | 将一个整数转换为一个字符
ord(x) | 将一个字符转换为它的整数值
hex(x) | 将一个整数转换为一个十六进制字符串
oct(x) | 将一个整数转换为一个八进制字符串

## 运算符

在实际开发中，如果搞不清楚运算符的优先级，可以使用括号来确保运算的执行顺序。

    # 运算符
    a = 10
    b = 20

    print(a + b)  # 加法，输出: 30
    print(a - b)  # 减法，输出: -10
    print(a * b)  # 乘法，输出: 200
    print(a / b)  # 除法，输出: 0.5
    print(a ** 2)  # 幂运算，输出: 100
    print(a % 3)  # 取模，输出: 1

    # 逻辑运算符
    print(a > b)  # 大于，输出: False
    print(a < b)  # 小于，输出: True
    print(a == b)  # 等于，输出: False
    print(a != b)  # 不等于，输出: True

    # 成员运算符
    s = 'Hello World'
    print('World' in s)  # 输出: True
    print('Python' not in s)  # 输出: True

运算符 | 描述
--- | ---
`[]` `[:]` | 下标，切片
`**` | 指数
`~` `+` `-` | 按位取反, 正负号
`*` `/` `%` `//` | 乘，除，模，整除
`+` `-` | 加，减
`>>` `<<` | 右移，左移
`&` | 按位与
`^` ` | `
`<=` `<` `>` `>=` | 小于等于，小于，大于，大于等于
`==` `!=` | 等于，不等于
`is` `is not` | 身份运算符
`in` `not in` | 成员运算符
`not` `or` `and` | 逻辑运算符
`=` `+=` `-=` `*=` `/=` `%=` `//=` `**=` `&=` ` | =`^=`>>=“<⇐`