第 2 章 变量与基本数据类型

在 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 官方推荐的代码风格指南中变量命名需严格遵循 "蛇形命名法",核心原则是 "见名知意"------ 通过变量名即可推断其存储的数据内容或用途,避免使用模糊的单字母名称(循环变量如ij除外)。

1. 强制性规则

规则 说明 正确示例 错误示例
蛇形命名法 多单词通过下划线 "_" 连接,所有字母小写 user_name(存储用户名)、order_total(存储订单总额) userName(驼峰命名法,多用于其他语言)、OrderTotal(首字母大写,用于 Python 类名)
合法字符范围 首字符只能为字母(a-z/A-Z)或下划线 "_",后续字符可包含字母、数字、下划线 _temp_data(临时数据)、age_1(第一个用户的年龄) 1age(数字开头)、user-name(包含非法字符 "-")
避开关键字 不得使用 Python 内置关键字(如ifforclassdef等) - if = 10if为条件判断关键字,不可用作变量名)
不覆盖内置函数 不得使用 Python 内置函数名(如liststrprintlen等) user_list(存储用户的列表,避免与list()函数冲突) list = [1, 2, 3](覆盖创建列表的内置函数list(),导致后续无法使用该函数)

2. 推荐性规范

  • 语义化命名 :变量名需准确反映数据含义,避免歧义。例如用product_count表示 "商品数量",而非模糊的datanum,符合代码可读性的核心要求。

  • 类型关联命名

    :针对集合类型变量,通过命名体现数据结构,便于快速识别数据类型:

    • 列表(有序可重复):使用复数形式,如user_idsproduct_names
    • 字典(键值对关联):使用 "xx_info" 或 "xx_dict",如user_infoconfig_dict
    • 集合(无序唯一):使用 "xx_set" 或直接体现去重含义,如active_user_setunique_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(复数)。其中intfloat为日常开发中最常用的类型,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)包括00.0None、空字符串("")、空列表([])、空字典({})等;"真值"(转换为True)包括非零数值、非空字符串、非空集合等,是条件测试的核心知识点。
  • 应用示例

    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 == 1False == 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__属性查看,是提升代码可维护性的核心工具。

    python 复制代码
    def 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,依次递减。
    ini 复制代码
    s: 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子串在字符串中的起始索引,未找到返回-1start/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)

📌 重点提示 :字符串是不可变类型 ------ 所有字符串方法(如replacestrip)都不会修改原字符串,而是返回一个新字符串。若需多次修改文本,建议先用列表暂存字符,最后用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)" 关联存储数据,键必须是不可变类型(如strinttuple),值可任意类型。其核心优势是 "高效查找"------ 通过键查询值的时间复杂度为 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}")

📌 重点提示 :字典的 "键" 必须是不可变类型 (如strint),列表等可变类型不能作为键(会引发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. 类型分类与特性

类型类别 包含类型 核心特性 修改示例
不可变类型 intfloatboolstrtuplecomplex 修改元素时创建新对象,原对象地址不变 a = 10a += 5 # 创建新对象15,a指向新地址print(id(a)) # 输出新地址(与原地址不同)
可变类型 listdictset 修改元素时直接修改原对象,不创建新对象 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异常处理,避免因数据格式错误导致程序崩溃,这是 "健壮性编程" 的核心要求。

相关推荐
2401_841495642 小时前
【机器学习】朴素贝叶斯法
人工智能·python·数学·算法·机器学习·概率论·朴素贝叶斯法
听潮阁2 小时前
Python 旅游数据分析平台【源码请评论区留言】
python·数据分析·旅游
扑克中的黑桃A3 小时前
Python快速入门专业版(八):字符串基础:创建、拼接与切片(10+实用代码案例)
python
时间醉酒3 小时前
逻辑回归(四):从原理到实战-训练,评估与应用指南
人工智能·python·算法·机器学习·逻辑回归
深度学习机器3 小时前
解密vLLM:基于nano-vllm源码剖析其推理加速之道
pytorch·llm·nvidia
计算机毕设残哥3 小时前
紧跟大数据技术趋势:食物口味分析系统Spark SQL+HDFS最新架构实现
大数据·hadoop·python·sql·hdfs·架构·spark
MediaTea3 小时前
Python 编辑器:Visual Studio Code
开发语言·ide·vscode·python·编辑器
深蓝电商API3 小时前
HTML 解析入门:用 BeautifulSoup 轻松提取网页数据
前端·爬虫·python·beautifulsoup
前路不黑暗@4 小时前
Java:代码块
java·开发语言·经验分享·笔记·python·学习·学习方法