在 Python 语言中,变量是数据存储与引用的基本单元,数据类型则决定了数据的组织方式及其可执行的操作。变量与数据类型共同构成程序设计的核心基础:前者通过符号名称与内存数据建立关联,后者规定数据的表现形式与运算规则。无论是文本记录、序列管理,还是多维结构的表达与处理,均依赖于这一基础体系。本章将基于 Python 语法规范,系统阐述变量的使用规则及基本数据类型的核心操作,并结合典型编程场景提供示例,以支持读者建立严谨而稳固的基础认知。
2.1 变量
变量是 Python 中数据的 "标识符号",其本质是将名称与内存中的数据对象建立关联,而非 "存储数据的容器"。通过变量,开发者无需记忆复杂的内存地址,仅通过名称即可调用数据。理解变量的赋值逻辑、命名规范与操作技巧,是编写可读性强、可维护性高的代码的前提,也是代码整洁性原则的基础。
2.1.1 变量的定义与使用
1. 赋值逻辑:对象引用的关联
Python 的变量赋值遵循 "对象引用模型"------ 赋值操作并非将数据 "存入" 变量,而是将变量名与内存中的数据对象建立引用关系。一个数据对象可被多个变量引用,若变量重新赋值,仅改变该变量的引用指向,不影响原数据对象。这一模型是理解变量操作的核心,直接影响后续函数传参、数据拷贝等场景的应用。
-
基础赋值示例:
python# 1. 创建整数对象20,将变量a与该对象关联 a = 20 # 2. 将变量b与变量a引用的同一对象(20)关联 b = a # 3. 创建整数对象30,将变量a的引用指向新对象 a = 30 print(a) # 输出:30(a指向新对象30) print(b) # 输出:20(b仍引用原对象20)
-
多变量并行赋值:适用于一次性为多个变量分配不同值,要求变量数量与值的数量严格一致,常用于数据解包场景,如提取多维度用户数据。
python# 场景:存储用户的姓名、年龄与等级信息 name, age, level = "Alice", 18, 3 print(name, age, level) # 输出:Alice 18 3
-
可迭代对象解包赋值:将列表、元组等可迭代对象的元素按顺序分配给变量,是处理批量结构化数据(如数据库查询结果)的常用方式。
python# 场景:从数据库查询结果(元组)中提取用户信息 user_info = ("Bob", 22, "bob@example.com") # 模拟查询返回的结构化数据 name, age, email = user_info # 解包元组元素至对应变量 print(email) # 输出:bob@example.com
-
默认值赋值:针对可选输入场景,当变量未获取有效数据时,通过逻辑判断赋予默认值,确保程序健壮性,符合用户输入处理的常见需求。
python# 场景:用户注册时手机号为可选项,未输入则使用默认值 username = "Charlie" phone = input("请输入手机号(可选):") # 若用户直接回车,phone为空字符串 phone = phone if phone else "未填写" # 空字符串时启用默认值 print(f"用户名:{username},手机号:{phone}")
📌 重点提示 :Python 中变量无需提前声明类型(动态类型特性),但在复杂项目中,推荐使用 "类型注解"(如user_id: int = 1001
)明确变量数据类型,提升代码可读性与团队协作效率。类型注解仅为提示性标记,不影响 Python 的动态类型特性。
2. 变量命名规范
Python 官方推荐的代码风格指南中变量命名需严格遵循 "蛇形命名法",核心原则是 "见名知意"------ 通过变量名即可推断其存储的数据内容或用途,避免使用模糊的单字母名称(循环变量如i
、j
除外)。
1. 强制性规则
规则 | 说明 | 正确示例 | 错误示例 |
---|---|---|---|
蛇形命名法 | 多单词通过下划线 "_" 连接,所有字母小写 | user_name (存储用户名)、order_total (存储订单总额) |
userName (驼峰命名法,多用于其他语言)、OrderTotal (首字母大写,用于 Python 类名) |
合法字符范围 | 首字符只能为字母(a-z/A-Z)或下划线 "_",后续字符可包含字母、数字、下划线 | _temp_data (临时数据)、age_1 (第一个用户的年龄) |
1age (数字开头)、user-name (包含非法字符 "-") |
避开关键字 | 不得使用 Python 内置关键字(如if 、for 、class 、def 等) |
- | if = 10 (if 为条件判断关键字,不可用作变量名) |
不覆盖内置函数 | 不得使用 Python 内置函数名(如list 、str 、print 、len 等) |
user_list (存储用户的列表,避免与list() 函数冲突) |
list = [1, 2, 3] (覆盖创建列表的内置函数list() ,导致后续无法使用该函数) |
2. 推荐性规范
-
语义化命名 :变量名需准确反映数据含义,避免歧义。例如用
product_count
表示 "商品数量",而非模糊的data
或num
,符合代码可读性的核心要求。 -
类型关联命名
:针对集合类型变量,通过命名体现数据结构,便于快速识别数据类型:
- 列表(有序可重复):使用复数形式,如
user_ids
、product_names
; - 字典(键值对关联):使用 "xx_info" 或 "xx_dict",如
user_info
、config_dict
; - 集合(无序唯一):使用 "xx_set" 或直接体现去重含义,如
active_user_set
、unique_emails
。
- 列表(有序可重复):使用复数形式,如
-
避免易混淆字符 :不使用小写字母
l
(易与数字1
混淆)、大写字母O
(易与数字0
混淆),例如用total_length
替代total_l
,避免代码歧义。
📌 重点提示 :推荐使用pylint
工具检查命名规范,通过pip install pylint
安装后,执行pylint 脚本名.py
,工具会自动提示命名不规范的变量,帮助养成符合 PEP 8 的编码习惯。
2.2 基本数据类型
Python 的基本数据类型可分为数值型 (处理数字)、字符串型 (处理文本)与集合型(处理多元素数据)三大类。不同类型的设计目的不同,例如数值型支持算术运算,字符串型支持文本处理,集合型支持多元素管理,掌握各类的核心特性与操作方法,是实现具体功能的基础。
2.2.1 数值型(Numbers)
数值型用于存储数字数据,支持加减乘除等算术运算,主要包括int
(整数)、float
(浮点数)、bool
(布尔值)与complex
(复数)。其中int
与float
为日常开发中最常用的类型,bool
常用于条件判断,complex
仅在科学计算等特殊场景使用。
1. int(整数)
int
类型表示没有小数部分的整数,支持正整数、负整数与零,Python 的int
无大小限制,可表示任意精度的整数。常用于计数、标识唯一 ID、表示状态码等场景。
-
常见应用场景:
- 计数场景:
order_id = 100001
(唯一标识订单的整数 ID)、success_count = 95
(成功提交的表单数量); - 状态标识:
status_code = 200
(HTTP 请求成功的状态码)、is_valid = 1
(用 1 表示 "有效" 状态)。
- 计数场景:
-
整数运算示例:
python# 场景:计算商品总价(数量×单价) quantity: int = 5 # 购买数量 price_per_unit: int = 20 # 单价(整数) total_price: int = quantity * price_per_unit print(f"商品总价:{total_price}元") # 输出:商品总价:100元
📌 重点提示 :Python 的int
无大小限制,可直接处理极大整数(如2 ** 1000
),无需手动处理 "大数溢出" 问题,体现了 Python 的易用性特性。
2. float(浮点数)
float
类型表示带有小数部分的数字,支持科学计数法(如1.2e3
表示 1200.0)。需注意:由于计算机以二进制存储小数,部分十进制小数(如 0.1、0.2)无法精确表示,可能导致运算精度偏差,需在金额计算等高精度场景中特殊处理。
-
常见应用场景:
- 精确数值场景:
product_price = 99.99
(商品单价)、temperature = 25.5
(室内温度); - 比例计算:
discount_rate = 0.8
(8 折优惠比例)、tax_rate = 0.09
(税率)。
- 精确数值场景:
-
精度问题与解决方案 : 直接使用
float
进行金额等高精度计算时,可能出现偏差:python# 问题示例:0.1 + 0.2 结果非预期 a: float = 0.1 b: float = 0.2 print(a + b) # 输出:0.30000000000000004(存在精度偏差)
解决精度问题需使用 Python 标准库
decimal
,通过指定精度控制计算结果:python# 解决方案:使用decimal模块处理金额计算 from decimal import Decimal, getcontext # 设置总有效数字精度为4(满足金额计算需求,如199.98需4位有效数字) getcontext().prec = 4 # 以字符串形式传入数值,避免float类型的精度损失 price: Decimal = Decimal("99.99") quantity: Decimal = Decimal("2") total: Decimal = price * quantity # 使用quantize固定小数位数为2,确保金额格式规范 total_formatted: Decimal = total.quantize(Decimal("0.00")) print(f"订单总价:{total_formatted}元") # 输出:订单总价:199.98元
📌 重点提示 :处理金额、税率等需精确到分 / 厘的场景时,严禁直接使用 float ,必须通过decimal
模块或 "整数分"(如 1 元 = 100 分)的方式规避精度问题,避免因计算偏差导致业务错误。
3. bool(布尔值)
bool
类型仅包含两个值:True
(逻辑 "真",对应整数 1)与False
(逻辑 "假",对应整数 0),主要用于条件判断,如判断 "用户是否登录""数据是否有效" 等场景。
-
核心特性:
- 自动类型转换:Python 中所有数据均可通过
bool()
函数转换为布尔值。其中,"假值"(转换为False
)包括0
、0.0
、None
、空字符串(""
)、空列表([]
)、空字典({}
)等;"真值"(转换为True
)包括非零数值、非空字符串、非空集合等,是条件测试的核心知识点。
- 自动类型转换:Python 中所有数据均可通过
-
应用示例:
python# 场景:判断用户是否满足"成年且有余额"的购物条件 is_adult: bool = True # 是否成年(True表示成年) has_balance: bool = True # 是否有余额(True表示有余额) can_purchase: bool = is_adult and has_balance # 逻辑与运算 print(f"是否允许购物:{can_purchase}") # 输出:是否允许购物:True
📌 重点提示 :bool
类型本质是int
的子类,True == 1
与False == 0
的结果均为True
,但在条件判断中应优先使用if is_adult:
而非if is_adult == True:
,避免逻辑冗余与潜在错误。
4. complex(复数)
complex
类型表示数学中的复数,格式为 "实部 + 虚部 j"(如3+4j
),其中j
表示虚数单位。仅在信号处理、量子计算等专业领域使用,日常开发中极少涉及,此处仅作基础了解。
-
基础操作示例:
python# 场景:简单复数运算 c1: complex = 3 + 4j c2: complex = 1 - 2j c_sum: complex = c1 + c2 # 复数加法 print(f"复数和:{c_sum}") # 输出:复数和:(4+2j) print(f"实部:{c_sum.real}") # 输出:实部:4.0 print(f"虚部:{c_sum.imag}") # 输出:虚部:2.0
2.2.2 字符串型(String)
字符串是由字符组成的有序序列,用于存储文本信息,通过单引号('
)、双引号("
)或三引号('''
/"""
)包裹。字符串是不可变类型(创建后无法修改单个字符),但可通过方法生成新字符串,是文本处理的核心工具。
1. 字符串的定义与引号选择
不同引号的适用场景不同,核心区别在于是否支持 "多行文本" 与 "引号嵌套",针对不同场景需合理选择:
引号类型 | 特点 | 适用场景 | 示例 |
---|---|---|---|
单引号' |
仅支持单行文本,内部嵌套单引号需转义(' ) |
简单单行文本(如短变量值) | name = 'Alice' (用户名称存储示例) |
双引号" |
仅支持单行文本,内部嵌套双引号需转义(" ) |
文本中包含单引号(避免转义) | quote = "He said 'Hello Python'" (引用文本示例) |
三引号''' /""" |
支持多行文本,内部可嵌套单 / 双引号(无需转义) | 1. 多行文本(如日志、长文档) 2. 函数 / 类的文档字符串(docstring) | note = '''今日任务:1. 编写列表操作代码 2. 测试功能正确性''' (任务记录示例) |
-
文档字符串(docstring):三引号常用于函数、类或模块的说明文档,可通过
__doc__
属性查看,是提升代码可维护性的核心工具。pythondef calculate_total(price: float, quantity: int) -> float: """计算商品总价(文档字符串) 参数: price (float): 商品单价(支持小数) quantity (int): 购买数量(非负整数) 返回: float: 商品总价(price × quantity) """ return price * quantity # 查看文档字符串 print(calculate_total.__doc__)
📌 重点提示:函数、类的文档字符串需包含 "功能描述""参数说明""返回值说明" 三部分,确保其他开发者无需阅读代码实现,仅通过文档字符串即可正确使用该函数 / 类。
2. 索引与切片:提取字符串片段
字符串是有序序列,可通过 "索引" 获取单个字符,通过 "切片" 获取连续字符片段,索引规则与切片语法严格遵循 Python 序列类型的通用规范,是序列操作的基础内容。
-
索引规则:
- 正索引:从左至右,第一个字符索引为
0
,依次递增; - 负索引:从右至左,最后一个字符索引为
-1
,依次递减。
inis: str = "Python" # 字符串长度为6,索引范围:0~5(正)、-1~-6(负) print(s[0]) # 输出:P(正索引0,第一个字符) print(s[-1]) # 输出:n(负索引-1,最后一个字符)
- 正索引:从左至右,第一个字符索引为
-
切片语法 : 语法格式:
s[start:end:step]
,其中:start
:切片起始位置(包含,默认值为0
);end
:切片结束位置(不包含,默认值为字符串长度);step
:切片步长(每次取字符的间隔,默认值为1
,负数表示反向切片)。 常用于日志解析、数据提取等场景:
python# 场景:从日志字符串中提取关键信息 log: str = "20240831_Order10001_Success" # 提取日期(前8个字符,start=0,end=8) date: str = log[0:8] print(f"日志日期:{date}") # 输出:日志日期:20240831 # 提取订单ID(从索引10到倒数8个字符前) order_id: str = log[10:-8] print(f"订单ID:{order_id}") # 输出:订单ID:10001 # 反向切片(倒序输出字符串,判断是否为回文) reversed_log: str = log[::-1] print(f"倒序日志:{reversed_log}") # 输出:倒序日志:ssuceS_10001redrO_13804202
📌 重点提示 :切片的end
参数是 "不包含" 的,例如log[0:8]
取的是索引 0~7 的字符,这是 Python 序列切片的通用规则,避免因 "包含 end" 的误解导致数据提取错误。
3. 常用字符串方法
字符串提供丰富的内置方法,用于实现文本清洗、分割、替换等操作,以下为日常开发中高频使用的方法:
方法 | 功能描述 | 应用场景示例 |
---|---|---|
strip([chars]) |
去除字符串首尾指定字符(默认去除空格、换行符\n 、制表符\t ) |
# 场景:清洗用户输入的手机号phone = " 13800138000 \n"clean_phone = phone.strip()print(f"清洗后手机号:{clean_phone}") # 输出:清洗后手机号:13800138000 |
split(sep=None, maxsplit=-1) |
按指定分隔符分割字符串,返回列表(sep 为分隔符,maxsplit 为最大分割次数) |
# 场景:解析CSV格式的用户数据csv_line = "Alice,18,female,alice@example.com"user_data = csv_line.split(",")print(f"解析后用户数据:{user_data}") # 输出:解析后用户数据:['Alice', '18', 'female', 'alice@example.com'] |
replace(old, new, count=-1) |
将字符串中的old 子串替换为new 子串(count 为最大替换次数,默认全部替换) |
# 场景:敏感词过滤content = "该内容包含敏感词:垃圾信息"filtered_content = content.replace("垃圾信息", "***")print(f"过滤后内容:{filtered_content}") # 输出:过滤后内容:该内容包含敏感词:*** |
find(sub, start=0, end=-1) |
查找sub 子串在字符串中的起始索引,未找到返回-1 (start /end 为查找范围) |
# 场景:检查日志是否包含错误信息log = "2024-08-31 [Error] 数据库连接超时"if log.find("Error") != -1: print("日志包含错误信息,需排查!") # 输出:日志包含错误信息,需排查! |
upper() /lower() |
upper() 将字符串转为全大写,lower() 转为全小写 |
# 场景:统一用户名格式(避免大小写差异导致的重复)username = "AlIcE"standard_username = username.lower()print(f"标准化用户名:{standard_username}") # 输出:标准化用户名:alice |
join(iterable) |
用当前字符串连接可迭代对象(如列表、元组)中的元素,返回新字符串 | # 场景:构建SQL查询的IN条件user_ids = ["101", "102", "103"]sql_in_clause = ",".join(user_ids)sql = f"SELECT * FROM users WHERE id IN ({sql_in_clause})"print(f"生成SQL:{sql}") # 输出:生成SQL:SELECT * FROM users WHERE id IN (101,102,103) |
📌 重点提示 :字符串是不可变类型 ------ 所有字符串方法(如replace
、strip
)都不会修改原字符串,而是返回一个新字符串。若需多次修改文本,建议先用列表暂存字符,最后用join
拼接,避免频繁创建新字符串导致性能损耗。
2.2.3 集合型
集合型用于存储多个元素,根据 "有序性""可变性""唯一性" 的差异,分为List
(列表)、Tuple
(元组)、Dictionary
(字典)与Set
(集合)四类,是数据结构化的核心工具。
类型 | 标识符号 | 核心特性 | 适用场景 |
---|---|---|---|
List(列表) | [] |
有序、可变、元素可重复 | 存储有序数据集(如待办事项、用户列表),需动态修改元素(任务管理、用户管理示例) |
Tuple(元组) | () (可省略) |
有序、不可变、元素可重复 | 存储固定数据集(如配置参数、多维度索引),避免误修改(配置管理、数据索引示例) |
Dictionary(字典) | {key: value} |
无序(Python 3.7 + 按插入顺序保留)、可变、键唯一 | 存储键值对关联数据(如用户信息、配置项),需通过键快速查询(用户信息管理、配置读取示例) |
Set(集合) | {} /set() |
无序、可变、元素唯一 | 数据去重、元素归属判断、集合运算(如交集、并集)(数据清洗、用户群体分析示例) |
1. List(列表)
列表是最常用的集合类型,支持动态添加、删除、修改元素,适用于存储有序且需频繁操作的数据集。
-
核心操作示例:
python# 场景:管理用户订单列表 orders: list[dict] = [] # 定义存储订单字典的列表 # 1. 新增元素(append添加单个元素,extend添加多个元素) orders.append({"id": 1001, "amount": 99.9, "status": "pending"}) new_orders: list[dict] = [ {"id": 1002, "amount": 199.9, "status": "pending"}, {"id": 1003, "amount": 299.9, "status": "paid"} ] orders.extend(new_orders) # 2. 修改元素(通过索引定位) orders[0]["status"] = "paid" # 将1001号订单状态改为"已支付" # 3. 删除元素(remove按值删除,pop按索引删除) orders.remove({"id": 1002, "amount": 199.9, "status": "pending"}) # 按值删除取消的订单 cancelled_order = orders.pop(-1) # 删除最后一个元素,返回删除的订单 # 4. 元素查询(in判断归属,结合生成器表达式) target_id = 1001 if any(order["id"] == target_id for order in orders): print(f"订单{target_id}存在") # 输出:订单1001存在 print(f"最终订单列表:{orders}") print(f"取消的订单:{cancelled_order}")
📌 重点提示 :列表的append()
方法仅能添加 "单个元素",若需添加多个元素,需使用extend()
或+=
,避免误将 "列表作为单个元素" 添加(如orders.append(new_orders)
会导致列表嵌套)。
2. Tuple(元组)
元组的元素一旦定义无法修改,可视为 "不可变的列表",适用于存储固定不变的数据(如配置参数、函数返回的多值),可避免数据被误修改。
-
核心特性示例:
python# 场景1:存储固定配置参数(窗口宽高) window_size: tuple[int, int] = (800, 600) # window_size[0] = 1024 # 报错:TypeError(元组元素不可修改) # 场景2:函数返回多值(本质是返回元组) def get_user_info(user_id: int) -> tuple[str, int, str]: """模拟从数据库查询用户信息,返回多值""" name: str = "Bob" age: int = 22 email: str = "bob@example.com" return name, age, email # 省略括号,本质返回元组 # 解包获取多值 name, age, email = get_user_info(102) print(f"用户邮箱:{email}") # 输出:用户邮箱:bob@example.com # 场景3:元组作为字典键(多维度索引) sales: dict[tuple[str, int], float] = { ("Beijing", 202408): 100000.0, ("Shanghai", 202408): 120000.0 } print(f"北京8月销售额:{sales[('Beijing', 202408)]}") # 输出:北京8月销售额:100000.0
📌 重点提示 :元组的 "不可变性" 仅针对 "元素本身",若元素是可变类型(如列表),则元素内部可修改(如tuple_with_list = (1, [2, 3]); tuple_with_list[1].append(4)
是合法的),需注意这种 "部分可变" 的特性,避免误判数据安全性。
3. Dictionary(字典)
字典通过 "键(key)- 值(value)" 关联存储数据,键必须是不可变类型(如str
、int
、tuple
),值可任意类型。其核心优势是 "高效查找"------ 通过键查询值的时间复杂度为 O (1),远快于列表的 O (n)。
-
核心操作示例:
python# 场景:管理用户信息 user: dict[str, str | int] = { "name": "Alice", "age": 18, "phone": "13800138000" } # 1. 新增键值对(setdefault避免覆盖已有值) user["address"] = "Beijing" # 新增地址(键不存在则添加) user.setdefault("email", "no-email@example.com") # 新增邮箱(键不存在则用默认值) # 2. 修改值(通过键定位) user["phone"] = "13700137000" # 更新手机号 # 3. 删除键值对(pop安全删除,避免键不存在报错) id_card = user.pop("id_card", None) # 尝试删除身份证号,不存在则返回None # 4. 查询值(get安全获取,避免键不存在报错) email = user.get("email", "unknown") # 获取邮箱,不存在则返回"unknown" # 5. 遍历键值对(items()返回所有键值对) print("用户信息:") for key, value in user.items(): print(f" {key}: {value}")
📌 重点提示 :字典的 "键" 必须是不可变类型 (如str
、int
),列表等可变类型不能作为键(会引发TypeError
)。同时,Python 3.7 + 版本开始保留字典的 "插入顺序",在此之前的版本字典是无序的,开发时需注意版本兼容性。
4. Set(集合)
集合的元素具有唯一性与无序性,核心用途是 "数据去重" 与 "集合运算"(如交集、并集、差集),元素必须是不可变类型。
-
核心操作示例:
python# 场景:分析活跃用户群体 # 昨日活跃用户 yesterday_active: set[int] = {101, 102, 103, 104} # 今日活跃用户 today_active: set[int] = {103, 104, 105, 106} # 1. 新增元素(add添加单个,update添加多个,自动去重) today_active.add(107) # 新增用户107 today_active.update([108, 109]) # 批量新增用户108、109 # 2. 删除元素(discard安全删除,不存在不报错) today_active.discard(109) # 删除用户109 # 3. 集合运算(交集、并集、差集) both_active = yesterday_active & today_active # 两日都活跃(交集) total_active = yesterday_active | today_active # 两日总活跃(并集) new_active = today_active - yesterday_active # 今日新增活跃(差集) print(f"两日都活跃用户:{both_active}") # 输出:两日都活跃用户:{103, 104} print(f"两日总活跃用户:{total_active}") # 输出:两日总活跃用户:{101, 102, ..., 108} print(f"今日新增活跃用户:{new_active}") # 输出:今日新增活跃用户:{105, 106, 107, 108}
📌 重点提示 :集合是 "无序" 的,遍历集合时无法保证元素顺序与添加顺序一致,若需有序且唯一的数据集,需使用collections.OrderedDict
(键有序)或 "列表 + 去重逻辑",避免依赖集合的顺序特性。
2.2.4 可变与不可变类型
区分 "可变类型" 与 "不可变类型" 是 Python 开发的核心知识点,两者的核心差异在于 "修改元素时是否创建新对象",直接影响函数传参、数据拷贝等操作,是避免 "隐性 bug" 的关键。
1. 类型分类与特性
类型类别 | 包含类型 | 核心特性 | 修改示例 |
---|---|---|---|
不可变类型 | int 、float 、bool 、str 、tuple 、complex |
修改元素时创建新对象,原对象地址不变 | a = 10a += 5 # 创建新对象15,a指向新地址print(id(a)) # 输出新地址(与原地址不同) |
可变类型 | list 、dict 、set |
修改元素时直接修改原对象,不创建新对象 | lst = [1, 2, 3]lst.append(4) # 直接修改原列表,不创建新对象print(id(lst)) # 输出原地址(无变化) |
2. 核心影响:函数传参的 "副作用"
Python 函数传参遵循 "对象引用传递"------ 传递的是变量指向的对象引用,而非变量本身或对象副本。这意味着:
- 传递不可变类型时,函数内修改会创建新对象,不影响外部变量;
- 传递可变类型时,函数内修改会直接修改原对象,影响外部变量。
python
# 场景:函数传参的差异
def modify_int(x: int) -> int:
"""修改整数(不可变类型)"""
x += 10
return x
def modify_list(lst: list[int]) -> list[int]:
"""修改列表(可变类型)"""
lst.append(10)
return lst
# 1. 传递不可变类型(int)
a: int = 5
new_a: int = modify_int(a)
print(f"外部变量a:{a}") # 输出:外部变量a:5(未受影响)
print(f"函数返回值:{new_a}") # 输出:函数返回值:15(新对象)
# 2. 传递可变类型(list)
lst: list[int] = [1, 2, 3]
new_lst: list[int] = modify_list(lst)
print(f"外部变量lst:{lst}") # 输出:外部变量lst:[1, 2, 3, 10](被修改)
print(f"函数返回值:{new_lst}") # 输出:函数返回值:[1, 2, 3, 10](与外部列表指向同一对象)
3. 解决方案:避免可变类型的意外修改
若需传递可变类型但不希望函数修改外部变量,需创建 "拷贝"(而非直接传递引用),常用copy
模块的copy()
(浅拷贝)与deepcopy()
(深拷贝):
python
import copy
def safe_modify_list(lst: list[int]) -> list[int]:
"""安全修改列表:创建深拷贝,不影响外部列表"""
lst_copy = copy.deepcopy(lst) # 深拷贝(即使列表包含可变元素,也完全复制)
lst_copy.append(10)
return lst_copy
lst: list[int] = [1, 2, 3]
new_lst: list[int] = safe_modify_list(lst)
print(f"外部列表lst:{lst}") # 输出:外部列表lst:[1, 2, 3](未修改)
print(f"修改后的拷贝:{new_lst}") # 输出:修改后的拷贝:[1, 2, 3, 10]
📌 重点提示 :copy()
(浅拷贝)仅复制 "表层元素",若列表包含可变子元素(如lst = [1, [2, 3]]
),浅拷贝后子元素仍共享引用;deepcopy()
(深拷贝)会递归复制所有元素,完全独立于原对象,需根据数据结构选择合适的拷贝方式。
2.2.5 数据类型转换
数据类型转换是 "数据清洗" 与 "数据处理" 的基础步骤 ------ 实际开发中,数据来源多样(如用户输入为字符串、API 返回为字典),需将数据转换为目标类型后才能进行计算或分析。转换分为 "显式转换"(手动调用函数)与 "隐式转换"(Python 自动转换)。
1. 显式转换:常用转换函数
以下转换函数为日常开发高频使用,覆盖大多数数据处理场景:
转换函数 | 功能描述 | 应用场景示例 |
---|---|---|
int(x, base=10) |
将x 转为整数(base 指定进制,默认 10) |
# 场景:用户输入的订单数量(字符串)转整数order_count_str = input("请输入订单数量:")order_count = int(order_count_str)print(f"订单数量:{order_count}(类型:{type(order_count)})") # 输出:订单数量:100(类型:<class 'int'>) |
float(x) |
将x 转为浮点数 |
# 场景:整数金额转浮点数(计算折扣)price_int = 99price_float = float(price_int)discount_price = price_float * 0.8print(f"折扣后价格:{discount_price}") # 输出:折扣后价格:79.2 |
str(x) |
将x 转为字符串 |
# 场景:拼接订单信息文本order_id = 1001amount = 99.9order_info = f"订单ID:{str(order_id)},金额:{str(amount)}元"print(order_info) # 输出:订单ID:1001,金额:99.9元 |
list(x) |
将可迭代对象x 转为列表 |
# 场景:元组转列表(便于修改)orders_tuple = (1001, 1002, 1003)orders_list = list(orders_tuple)orders_list.append(1004)print(f"修改后的列表:{orders_list}") # 输出:修改后的列表:[1001, 1002, 1003, 1004] |
dict(x) |
将可迭代键值对x 转为字典 |
# 场景:键列表与值列表转字典keys = ["name", "age", "phone"]values = ["Alice", 18, "13800138000"]user_dict = dict(zip(keys, values))print(f"生成的字典:{user_dict}") # 输出:生成的字典:{'name': 'Alice', 'age': 18, 'phone': '13800138000'} |
set(x) |
将可迭代对象x 转为集合(自动去重) |
# 场景:用户ID列表去重user_ids = [101, 102, 102, 103, 103]unique_ids = list(set(user_ids))print(f"去重后的ID:{unique_ids}") # 输出:去重后的ID:[101, 102, 103](顺序可能变化) |
2. 隐式转换:Python 自动触发
隐式转换仅发生在 "兼容类型的运算" 中,Python 会自动将 "低精度类型" 转为 "高精度类型",避免数据丢失:
python
# 场景1:整数 + 浮点数 → 浮点数(int自动转为float)
a: int = 10
b: float = 3.14
c: float = a + b
print(f"结果类型:{type(c)},结果值:{c}") # 输出:结果类型:<class 'float'>,结果值:13.14
# 场景2:布尔值 + 整数 → 整数(bool自动转为int,True=1,False=0)
is_adult: bool = True
age: int = 18
total: int = age + is_adult
print(f"计算结果:{total}") # 输出:计算结果:19(18 + 1)
3. 安全转换:处理转换失败
实际开发中,数据可能不符合转换规则(如用户输入 "abc" 却需转为整数),直接转换会引发ValueError
,需用try-except
捕获异常,确保程序健壮性:
python
def safe_to_int(input_str: str) -> int:
"""安全将字符串转为整数,转换失败返回默认值0"""
try:
return int(input_str)
except ValueError:
print(f"无效输入:'{input_str}',请输入合法整数")
return 0
# 测试:有效输入
order_count1 = safe_to_int("100")
print(f"有效输入结果:{order_count1}") # 输出:有效输入结果:100
# 测试:无效输入
order_count2 = safe_to_int("abc")
print(f"无效输入结果:{order_count2}") # 输出:无效输入结果:0(并打印错误提示)
📌 重点提示 :处理用户输入、API 返回等 "不可控数据" 时,必须对类型转换添加try-except
异常处理,避免因数据格式错误导致程序崩溃,这是 "健壮性编程" 的核心要求。