数据类型
# 数据类型
在编程中,数据类型 是对数据进行分类的"标签",它告诉计算机如何解释、存储和操作这些数据。Python 拥有一套丰富且设计精良的内置数据类型,深入理解它们是编写高效、健壮代码的关键。
# 1. 理解数据类型:编程的基石
- 为什么需要数据类型? 数据类型决定了变量可以存储什么样的数据,以及可以对这些数据执行哪些操作。例如,整数可以进行数学运算,而字符串可以进行文本处理。
- Python 的动态类型:与 C++ 或 Java 等静态类型语言不同,Python 是一门 动态类型 语言。这意味着你无需在创建变量时显式声明其类型,Python 解释器会在代码运行时自动推断。
# Python 会自动识别类型
age = 20
name = "Alice"
print(f"age 的类型是: {type(age)}") # 输出: age 的类型是: <class 'int'>
print(f"name 的类型是: {type(name)}") # 输出: name 的类型是: <class 'str'>
1
2
3
4
5
6
2
3
4
5
6
# 2. 数字类型 (Numeric Types)
用于表示数值,是所有计算的基础。
# 2.1 整数 (int)
整数是没有小数部分的数字,可以是正数、负数或零。
- 核心特点:Python 的整数支持 任意精度(或称"无限精度")。只要你的计算机内存足够,它就能精确表示任何大小的整数,无需担心溢出问题。
- 基础运算:
a = 10 b = 3 # 基本算术运算 print(f"{a} + {b} = {a + b}") # 输出: 10 + 3 = 13 print(f"{a} - {b} = {a - b}") # 输出: 10 - 3 = 7 print(f"{a} * {b} = {a * b}") # 输出: 10 * 3 = 30 print(f"{a} / {b} = {a / b}") # 输出: 10 / 3 = 3.333... (除法总是返回浮点数) print(f"{a} // {b} = {a // b}") # 输出: 10 // 3 = 3 (整除) print(f"{a} % {b} = {a % b}") # 输出: 10 % 3 = 1 (取余) print(f"{a} ** {b} = {a ** b}") # 输出: 10 ** 3 = 1000 (幂运算) # 比较运算 print(f"{a} > {b} is {a > b}") # 输出: 10 > 3 is True print(f"{a} == {b} is {a == b}") # 输出: 10 == 3 is False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 - 不同进制表示:
decimal_num = 100 # 默认十进制 binary_num = 0b1100100 # 二进制 (以 0b 开头) octal_num = 0o144 # 八进制 (以 0o 开头) hex_num = 0x64 # 十六进制 (以 0x 开头) # 它们的值都是 100 print(binary_num == octal_num == hex_num) # 输出: True # `bit_length()` 方法返回表示该数字所需的最小二进制位数 print(f"{decimal_num} 的二进制长度是: {decimal_num.bit_length()}") # 输出: 100 的二进制长度是: 7 (因为 1100100 是 7 位)
1
2
3
4
5
6
7
8
9
10
# 2.2 浮点数 (float)
浮点数是带有小数的数字,用于表示现实世界中的测量值、比例等。
- 核心特点:包含小数部分。可以使用科学计数法表示。
- 基础运算:
x = 3.14 y = 2.0 # 基本运算 print(f"{x} + {y} = {x + y}") # 输出: 3.14 + 2.0 = 5.14 print(f"{x} * {y} = {x * y}") # 输出: 3.14 * 2.0 = 6.28 print(f"{x} / {y} = {x / y}") # 输出: 3.14 / 2.0 = 1.57 # 科学计数法 large_num = 1.23e6 # 1.23 * 10^6 small_num = 1.23e-6 # 1.23 * 10^(-6) print(large_num) # 输出: 1230000.0 print(small_num) # 输出: 0.00000123
1
2
3
4
5
6
7
8
9
10
11
12
13 - 精度陷阱:计算机内部使用二进制存储浮点数,这导致大多数十进制小数无法被精确表示,从而在计算时产生微小的、可累积的误差。
# 精度误差示例 print(f"0.1 + 0.2 = {0.1 + 0.2}") # 期望是 0.3,实际输出: 0.1 + 0.2 = 0.30000000000000004 # 如何应对精度问题? # 对于需要高精度计算的场景(如金融、科学计算),应使用 `decimal` 模块。 from decimal import Decimal print(Decimal('0.1') + Decimal('0.2')) # 输出: 0.3
1
2
3
4
5
6
7
# 2.3 布尔值 (bool)
布尔值代表逻辑上的"真"与"假",只有两个值:True
和 False
。
- 本质揭示:在 Python 中,布尔值是整数的子类,
True
在数值上等同于1
,False
等同于0
。这意味着它们可以参与数学运算(但不推荐这样做)。 - 基础逻辑运算:
a = True b = False # 逻辑运算 print(f"{a} and {b} = {a and b}") # 输出: True and False = False print(f"{a} or {b} = {a or b}") # 输出: True or False = True print(f"not {a} = {not a}") # 输出: not True = False # 比较运算返回布尔值 print(f"5 > 3 is {5 > 3}") # 输出: 5 > 3 is True print(f"5 == 3 is {5 == 3}") # 输出: 5 == 3 is False # 布尔值可以参与运算(不推荐) print(True + 1) # 输出: 2 (因为 True 被当作 1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14 - 真值测试 (Truthiness):Python 的一个强大之处在于,任何对象都可以被置于逻辑上下文中(如
if
语句)进行真假判断。- 被视为
False
的值:None
False
- 任何值为零的数字类型:
0
,0.0
,0j
- 任何空序列或集合:
""
,[]
,()
,{}
- 自定义类中,实现了
__bool__()
方法且返回False
或__len__()
方法返回0
的对象。
- 其他所有值默认都被视为
True
。
- 被视为
def check_user(user_list):
if user_list: # 如果列表不为空 (被视为 True)
print(f"欢迎, {user_list[0]}!")
else: # 如果列表为空 (被视为 False)
print("没有用户。")
check_user(["Alice"]) # 输出: 欢迎, Alice!
check_user([]) # 输出: 没有用户。
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 3. 序列类型 (Sequence Types)
序列是一块有序的数据集合,其内的每个元素都可通过 索引 (Index) 访问。Python 中有三种主要的序列类型。
# 3.1 字符串 (str) - 不可变文本序列
字符串是用于表示文本的字符序列。
- 核心特点:不可变 (Immutable)。一旦字符串被创建,其任何部分都不能被直接修改。对字符串的所有操作(如拼接、替换)都会返回一个 新的 字符串对象。
- 定义方式:可以使用单引号
'...'
、双引号"..."
或三引号'''...'''
/"""..."""
(用于多行文本)来定义。 - 基础操作:
# 字符串创建 name = "Alice" message = 'Hello, World!' # 字符串拼接 first = "Hello" second = "World" result = first + " " + second print(result) # 输出: Hello World # 字符串重复 stars = "*" * 5 print(stars) # 输出: ***** # 获取长度 print(len(name)) # 输出: 5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 - 索引和切片:
text = "Python" # 索引 (从0开始) print(text[0]) # 输出: 'P' (第一个字符) print(text[-1]) # 输出: 'n' (最后一个字符) # 切片 [start:end:step] print(text[1:4]) # 输出: 'yth' (索引1到3,不含4) print(text[:3]) # 输出: 'Pyt' (从开始到索引2) print(text[2:]) # 输出: 'thon' (从索引2到结束) print(text[::2]) # 输出: 'Pto' (步长为2,隔一个取一个) print(text[::-1]) # 输出: 'nohtyP' (反转字符串)
1
2
3
4
5
6
7
8
9
10
11
12 - f-string 格式化 (推荐):自 Python 3.6 起,f-string 提供了最简洁、最高效的字符串格式化方式。
name = "Alice" age = 30 message = f"用户: {name}, 年龄: {age}." # 直接在字符串中嵌入变量 print(message) # 输出: 用户: Alice, 年龄: 30.
1
2
3
4 - 常用方法一览:
name.upper()
/name.lower()
: 返回大小写转换后的新字符串。message.strip()
: 去除首尾的空白字符。message.split(',')
: 按指定分隔符分割字符串,返回一个列表。name.find('i')
: 查找子字符串的位置,找不到返回 -1。message.replace('用户', '客户')
: 替换子字符串。
# 实际使用示例 text = " Hello, World! " print(f"'{text.strip()}'") # 输出: 'Hello, World!' print(text.upper()) # 输出: ' HELLO, WORLD! ' print(text.split(',')) # 输出: [' Hello', ' World! '] print(text.replace('World', 'Python')) # 输出: ' Hello, Python! '
1
2
3
4
5
6
# 3.2 列表 (list) - 可变通用序列
列表是最灵活的数据结构,它可以存储任意类型的元素,并且可以随时增、删、改、查。
- 核心特点:可变 (Mutable)、有序。
- 定义方式:使用方括号
[]
定义,元素间用逗号,
分隔。 - 基础操作:
# 创建列表 numbers = [1, 2, 3, 4, 5] mixed = [1, "hello", 3.14, True] empty = [] # 访问元素 print(numbers[0]) # 输出: 1 (第一个元素) print(numbers[-1]) # 输出: 5 (最后一个元素) # 修改元素 print(f"修改前: {numbers}") # 输出: 修改前: [1, 2, 3, 4, 5] numbers[2] = 10 print(f"修改后: {numbers}") # 输出: 修改后: [1, 2, 10, 4, 5] # 获取长度 print(len(numbers)) # 输出: 5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 - 切片操作:
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] print(numbers[2:5]) # 输出: [2, 3, 4] print(numbers[:3]) # 输出: [0, 1, 2] print(numbers[7:]) # 输出: [7, 8, 9] print(numbers[::2]) # 输出: [0, 2, 4, 6, 8] (步长为2) print(numbers[::-1]) # 输出: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] (反转)
1
2
3
4
5
6
7 - 遍历列表:
fruits = ["apple", "banana", "orange"] # 方法1:直接遍历元素 print("--- 方法1 ---") for fruit in fruits: print(fruit) # 输出: # apple # banana # orange # 方法2:遍历索引 print("--- 方法2 ---") for i in range(len(fruits)): print(f"{i}: {fruits[i]}") # 输出: # 0: apple # 1: banana # 2: orange # 方法3:同时获取索引和元素 (推荐) print("--- 方法3 ---") for i, fruit in enumerate(fruits): print(f"{i}: {fruit}") # 输出: # 0: apple # 1: banana # 2: orange
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 - 常用操作:
scores = [88, 92, 75] print(f"初始列表: {scores}") # 输出: 初始列表: [88, 92, 75] scores.append(95) # 末尾添加 print(f"append(95)后: {scores}") # 输出: append(95)后: [88, 92, 75, 95] scores.insert(1, 90) # 在索引1处插入 print(f"insert(1, 90)后: {scores}") # 输出: insert(1, 90)后: [88, 90, 92, 75, 95] removed_score = scores.pop()# 弹出并返回末尾元素 print(f"pop()后列表: {scores}") # 输出: pop()后列表: [88, 90, 92, 75] print(f"被弹出的元素: {removed_score}") # 输出: 被弹出的元素: 95 del scores[0] # 删除第一个元素 print(f"del scores[0]后: {scores}") # 输出: del scores[0]后: [90, 92, 75] scores.sort(reverse=True) # 原地降序排序 print(f"sort()后: {scores}") # 输出: sort()后: [92, 90, 75]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 - 列表推导式 (List Comprehension):一种优雅、高效地创建列表的方式。
# 创建一个 0 到 9 的平方数列表 squares = [x**2 for x in range(10)] print(squares) # 输出: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # 带条件的列表推导式 even_squares = [x**2 for x in range(10) if x % 2 == 0] print(even_squares) # 输出: [0, 4, 16, 36, 64]
1
2
3
4
5
6
7
# 3.3 元组 (tuple) - 不可变数据记录
元组与列表非常相似,但其核心区别在于它是 不可变的,像一条"只读"的列表。
- 核心特点:不可变 (Immutable)、有序。一旦创建,其内容无法更改。
- 定义方式:主要使用圆括号
()
定义。定义单个元素的元组时,必须在元素后加一个逗号(1,)
以区别于普通的括号运算。 - 基础操作:
# 创建元组 coordinates = (10, 20) single_item = (42,) # 注意这个逗号,没有它 single_item 就是整数 42 empty_tuple = () # 访问元素 print(f"第一个元素: {coordinates[0]}") # 输出: 第一个元素: 10 # 元组解包 (Tuple Unpacking) x, y = coordinates print(f"x = {x}, y = {y}") # 输出: x = 10, y = 20 # 获取长度 print(len(coordinates)) # 输出: 2 # 注意:不能修改元组 # coordinates[0] = 5 # 这会引发 TypeError
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 - 为何需要元组?:
- 性能:由于不可变,Python 在内部可以进行一些优化,元组的创建和访问速度通常比列表稍快。
- 安全:保护数据不被意外修改,尤其适合作为函数返回值或多线程环境。
- 作为字典的键:只有不可变类型才能作为字典的键,元组符合这个要求。
# 用作函数返回值,确保数据不被调用方修改 def get_user_info(): return ("Alice", 30, "Admin") user_data = get_user_info() print(f"用户信息: {user_data}") # 输出: 用户信息: ('Alice', 30, 'Admin') # 用作字典的键 location_data = { (31.23, 121.47): "上海", (39.90, 116.40): "北京" } print(f"坐标(31.23, 121.47)对应的城市是: {location_data[(31.23, 121.47)]}") # 输出: ...是: 上海
1
2
3
4
5
6
7
8
9
10
11
12
13
# 4. 映射类型:字典 (dict)
字典是一种通过 键 (Key) 来高效存取 值 (Value) 的数据结构,是 Python 中极其重要的数据类型。
- 核心特点:可变 (Mutable),由键值对 (
key: value
) 组成。键必须是唯一的、不可变的类型(如int
,str
,tuple
),值则可以是任意类型。 - 定义方式:使用花括号
{}
定义。 - 基础操作:
# 创建字典 person = {"name": "Alice", "age": 25} print(f"初始字典: {person}") # 输出: 初始字典: {'name': 'Alice', 'age': 25} # 访问值 print(f"姓名: {person['name']}") # 输出: 姓名: Alice # 修改值 person["age"] = 26 print(f"修改年龄后: {person}") # 输出: 修改年龄后: {'name': 'Alice', 'age': 26} # 添加新键值对 person["city"] = "北京" print(f"添加城市后: {person}") # 输出: 添加城市后: {'name': 'Alice', 'age': 26, 'city': '北京'} # 检查键是否存在 if "name" in person: print("键 'name' 存在") # 输出: 键 'name' 存在
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 - 常用操作:
student = {"name": "Bob", "age": 22, "major": "CS"} # 安全地获取值 (推荐) # 若 'city' 键不存在,返回默认值 '未知',而不会报错 city = student.get("city", "未知") print(f"城市: {city}") # 输出: 城市: 未知 # 删除键值对 del student["major"] print(f"删除专业后: {student}") # 输出: 删除专业后: {'name': 'Bob', 'age': 22} # 遍历字典 print("--- 遍历字典 ---") for key, value in student.items(): print(f"{key}: {value}") # 输出: # name: Bob # age: 22
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 - 字典推导式 (Dictionary Comprehension):
nums = [1, 2, 3] squared_dict = {x: x**2 for x in nums} print(squared_dict) # 输出: {1: 1, 2: 4, 3: 9}
1
2
3
# 5. 集合类型 (set)
集合是一个无序、不重复的元素集合,其设计灵感来源于数学中的集合概念。
- 核心特点:可变 (Mutable)、无序、元素唯一。
- 定义方式:使用花括号
{}
或set()
函数定义。注意:创建一个空集合必须用set()
,因为{}
用于创建空字典。 - 基础操作:
# 创建集合 numbers = {1, 2, 3, 2, 1} # 重复元素会被自动忽略 print(f"初始集合: {numbers}") # 输出: 初始集合: {1, 2, 3} # 添加元素 numbers.add(4) print(f"add(4)后: {numbers}") # 输出: add(4)后: {1, 2, 3, 4} # 删除元素 numbers.remove(1) # 如果元素不存在会报错 print(f"remove(1)后: {numbers}") # 输出: remove(1)后: {2, 3, 4} numbers.discard(10) # 如果元素不存在不会报错 print(f"discard(10)后: {numbers}") # 输出: discard(10)后: {2, 3, 4} # 检查元素是否存在 (非常快) print(f"2 是否在集合中? {2 in numbers}") # 输出: 2 是否在集合中? True
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 - 核心应用:
- 高效去重:将列表等其他序列转换为集合,是 Python 中最快的去重方法。
- 成员资格测试:检查一个元素是否存在于集合中,其速度远快于列表。
- 数学集合运算:轻松实现并集、交集、差集等。
# 高效去重 my_list = [1, 2, 'a', 'b', 2, 'a'] unique_elements = set(my_list) print(f"列表去重后: {unique_elements}") # 输出: 列表去重后: {1, 2, 'a', 'b'} (顺序可能不同) # 集合运算 frontend_devs = {'HTML', 'CSS', 'JavaScript', 'React'} backend_devs = {'Python', 'Java', 'JavaScript'} # 交集 (&):全栈开发者 fullstack_devs = frontend_devs & backend_devs print(f"交集: {fullstack_devs}") # 输出: 交集: {'JavaScript'} # 并集 (|):所有技术栈 all_skills = frontend_devs | backend_devs print(f"并集: {all_skills}") # 输出: 并集: {'CSS', 'React', 'HTML', 'Java', 'Python', 'JavaScript'} (顺序可能不同) # 差集 (-):只会前端,不会后端的 frontend_only = frontend_devs - backend_devs print(f"差集: {frontend_only}") # 输出: 差集: {'CSS', 'React', 'HTML'} (顺序可能不同)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 6. 特殊类型:NoneType
NoneType
类型只有一个唯一的值 None
。它是一个特殊的常量,用于表示"空"、"无值"或"不存在"。
- 核心用途:
- 作为函数没有
return
语句时的默认返回值。 - 作为函数可选参数的默认值,以判断该参数是否被调用者提供。
- 初始化一个未来会存放某个对象的变量,表示其初始状态为空。
def greet(name=None): if name is None: # 判断是否为 None,推荐使用 is print("Hello, guest!") else: print(f"Hello, {name}!") greet() # 输出: Hello, guest! greet("Alice") # 输出: Hello, Alice!
1
2
3
4
5
6
7
8 - 作为函数没有
# 7. 可变与不可变类型总结
理解一个数据类型是可变的还是不可变的,对于避免程序中难以察觉的 bug至关重要。
- 不可变 (Immutable):创建后,其值(或内部状态)不能被改变。如
int
,float
,bool
,str
,tuple
。对这类变量的"修改"实际上是创建了一个全新的对象,并将变量名指向这个新对象。 - 可变 (Mutable):创建后,其值(或内部状态)可以被改变。如
list
,dict
,set
。修改这类变量是在其原始内存地址上直接进行操作,不会创建新对象。
类型 | 可变性 | 关键行为 |
---|---|---|
int , float , bool | 不可变 | 赋值操作 x = x + 1 创建新对象。 |
str | 不可变 | s += "b" 创建一个新字符串。 |
tuple | 不可变 | 无法执行 t[0] = ... 等修改操作。 |
list | 可变 | li.append(3) 在原列表上修改。 |
dict | 可变 | d['a'] = 1 在原字典上修改。 |
set | 可变 | s.add(3) 在原集合上修改。 |
# 8. 如何检查数据类型
Python 提供了两个主要的内置函数来帮助我们检查变量的类型。
type()
:精确地返回一个对象的类型。通常用于调试。isinstance(object, classinfo)
:检查一个对象是否是指定类或其任意子类的实例。在进行类型检查时,官方更推荐使用isinstance()
,因为它能正确处理继承关系,使代码更健壮。
x = 10
y = [1, 2]
# 使用 type()
print(type(x) == int) # 输出: True
# 使用 isinstance() - 更优雅、更健壮的方式
print(isinstance(x, int)) # 输出: True
# 检查是否为多种类型之一
print(isinstance(y, (list, tuple))) # 输出: True (因为 y 是一个列表)
# isinstance 能正确处理继承关系
print(isinstance(True, int)) # 输出: True (因为 bool 是 int 的子类)
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
编辑此页 (opens new window)
上次更新: 2025/07/23, 06:33:16