Python3 数据类型转换新手实战指南

Python3 数据类型转换新手实战指南

别被"数据类型转换"这个名词唬住------说白了就是"把一种格式的数据变成另一种格式"。你平时把Excel表格另存为CSV,把Word转成PDF,干的也是同样的事。


WEB项目地址:演示地址 安卓APP下载地址:演示地址

① 常见数据类型特征与转换场景解析

先快速过一遍 Python 里最常用的几种数据,知道它们长什么样、用来干嘛就够了:

类型 写法 特点 转换最常遇见的场景
字符串(str) "123"'hello' 引号包着,不能直接做数学运算 用户输入全是字符串,要算数必须转
整数(int) 5-3 没小数点,精确 从文件读到的数字带换行符,要转
浮点数(float) 3.14-0.5 带小数点,有精度误差 计算金额、百分比时常用
列表(list) [1,2,3] 有序、可改、可重复 数据排序、批量处理
元组(tuple) (1,2,3) 有序、不可改、可重复 函数返回多个值、字典的键
集合(set) {1,2,3} 无序、不可改元素、自动去重 去掉重复数据、找交集差集
字典(dict) {"name":"小明"} 键值对、键不可重复 处理JSON、配置信息

什么时候需要转换?

你从 input() 拿到的全是字符串,但你要算账 → 转数字;你要把数字存到数据库里当文本字段 → 转字符串;你有个列表里有重复数据 → 转集合去重再转回来。就这么回事。


② 字符串转数值型的核心方法与陷阱

最基础的操作:

python 复制代码
# 字符串 → 整数
num_str = "123"
num = int(num_str)        # 123

# 字符串 → 浮点数
pi_str = "3.14159"
pi = float(pi_str)        # 3.14159

就这么简单?对,就这么简单。但坑全在细节里

坑一:字符串里有多余的空格或换行

python 复制代码
s = "  456\n"      # 从文件读出来的经常这样
num = int(s.strip())   # 先 strip() 再转,养成习惯

坑二:字符串里有不可见字符

python 复制代码
s = "123\u200b"    # 带了个零宽空格,肉眼看不见
# int(s) 直接报错 ValueError
import re
clean = re.sub(r'[\u200b\u200c\u200d]', '', s)   # 先清洗

坑三:数字带千分位逗号

python 复制代码
s = "1,234,567"
num = int(s.replace(",", ""))    # 去掉逗号再转

坑四:带正负号没问题,但带加号中间有空格不行

python 复制代码
int("+123")    # 123  ✅
int("-123")    # -123 ✅
int("+ 123")   # 报错 ❌

稳妥的转换写法:

python 复制代码
def safe_int(s, default=0):
    """安全转整数,失败了返回默认值"""
    if s is None:
        return default
    try:
        # 先清理:去空格、去不可见字符
        cleaned = ''.join(ch for ch in str(s).strip() if ch.isprintable() and ch != '\u200b')
        return int(cleaned)
    except (ValueError, TypeError):
        return default

print(safe_int("  123  "))    # 123
print(safe_int("abc"))        # 0
print(safe_int(None))         # 0

浮点数还有一个特殊坑:

python 复制代码
float("3.14")     # 3.14 ✅
float("3,14")     # 报错!欧洲写法,逗号当小数点,Python不认

③ 数值型转字符串的格式化技巧

数字转字符串简单,str(123) 完事。但怎么转成想要的样子才是重点。

基本转换:

python 复制代码
num = 3.14159
print(str(num))           # "3.14159"
print(repr(num))          # 和 str 基本一样,调试时用

控制小数位数(必备技能):

python 复制代码
price = 19.9
print(f"{price:.2f}")     # "19.90"  保留两位小数,自动四舍五入
print(f"{price:.0f}")     # "20"     保留0位小数,变成整数格式但类型还是字符串

# 老式写法(你还会见到,认识就行)
print("%.2f" % price)     # "19.90"
print(format(price, ".2f"))  # "19.90"

千分位分隔(处理大数字):

python 复制代码
big = 1234567.89
print(f"{big:,.2f}")      # "1,234,567.89"
print(f"{big:,.0f}")      # "1,234,568"

补零和对齐(生成固定长度编号):

python 复制代码
num = 42
print(f"{num:05d}")       # "00042"  宽度5,不足补0
print(f"{num:>5d}")       # "   42"  右对齐,宽度5
print(f"{num:<5d}")       # "42   "  左对齐
print(f"{num:^5d}")       # " 42  "  居中对齐

# 十六进制、二进制
print(f"{255:x}")         # "ff"  小写十六进制
print(f"{255:X}")         # "FF"  大写十六进制
print(f"{255:b}")         # "11111111"  二进制

什么时候用这些? 生成报告、导出Excel、打印购物小票、生成订单编号,全用得上。


④ 列表元组集合间的相互转换实操

这三种类型互相转,基本就一个函数的事,但转完特性变了,得清楚自己需要什么。

python 复制代码
# 列表 ↔ 元组
my_list = [1, 2, 3, 3]
my_tuple = tuple(my_list)        # (1, 2, 3, 3)
back_to_list = list(my_tuple)    # [1, 2, 3, 3]

# 列表 ↔ 集合(去重神器)
my_set = set(my_list)            # {1, 2, 3}  注意重复的3没了,顺序也不保证
back_to_list = list(my_set)      # [1, 2, 3]  顺序不确定

# 元组 ↔ 集合
my_set = set((1, 2, 3, 3))       # {1, 2, 3}
my_tuple = tuple({1, 2, 3})      # (1, 2, 3)

手敲实战:

python 复制代码
# 场景:统计一篇文章里有哪些不同的单词
text = "hello world hello python world"
words = text.split()              # ['hello', 'world', 'hello', 'python', 'world']
unique_words = list(set(words))   # ['hello', 'world', 'python']  去重了,但顺序乱了

# 如果要保持原顺序去重(面试常考)
seen = set()
ordered_unique = []
for w in words:
    if w not in seen:
        seen.add(w)
        ordered_unique.append(w)
print(ordered_unique)   # ['hello', 'world', 'python']  顺序保留

拆解字符串 ↔ 列表(日常高频):

python 复制代码
s = "苹果,香蕉,橙子"
fruits = s.split(",")          # ['苹果', '香蕉', '橙子']  按逗号拆成列表
fruits = s.split("、")          # 按顿号拆也行

# 合并回去
new_s = ",".join(fruits)        # '苹果,香蕉,橙子'
new_s = " | ".join(fruits)      # '苹果 | 香蕉 | 橙子'

# 按固定宽度切割
s = "ABC123DEF"
import re
parts = re.findall(r'.{3}', s)  # ['ABC', '123', 'DEF']

⑤ 布尔值与其他类型的隐式转换规则

这部分最难搞的不是语法,是你以为它怎么转和你觉得它应该怎么转之间的落差。

显式转布尔值:

python 复制代码
print(bool(0))          # False
print(bool(1))          # True
print(bool(-5))         # True  (负数也是True)
print(bool(""))         # False
print(bool("hello"))    # True
print(bool([]))         # False
print(bool([1,2]))      # True
print(bool(None))       # False
print(bool({}))         # False

记住口诀:空、零、None → False,其他都是 True

隐式转换(最容易出bug的地方):

python 复制代码
# 数字和布尔值运算时,True当1,False当0
print(True + 5)          # 6
print(False * 10)        # 0
print(True == 1)         # True
print(False == 0)        # True

# 但注意 True is 1 是 False,因为 is 比较的是内存地址

常见实战坑:

python 复制代码
# 你想判断用户是否输入了内容,结果写了
user_input = input("输入年龄:")
if user_input == True:    # ❌ 永远不成立,因为 user_input 是字符串
    print("有输入")

# 正确写法
if user_input:            # ✅ 只要字符串非空就True
    print("有输入")

# 另一个经典错误
count = 0
if count:                 # False,不执行
    print("有数据")
# 想判断是否等于0应该用 if count == 0

条件表达式里的自动转换(写简洁代码的核心):

python 复制代码
# 这样写很啰嗦
if len(my_list) > 0:
    result = "有数据"
else:
    result = "空"

# 可以简化成
result = "有数据" if my_list else "空"

# 或者更直接
result = my_list or "空列表"   # 如果my_list非空取它自己,否则取"空列表"

⑥ 自定义对象转标准数据类型的策略

当你开始写类的时候,总会遇到需要把自定义对象转成字符串、数字或字典的情况。

最基础的:实现 __str____repr__

python 复制代码
class Student:
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score
    
    def __str__(self):
        # print() 和 str() 时调用
        return f"学生:{self.name}({self.age}岁,成绩{self.score}分)"
    
    def __repr__(self):
        # 调试时直接敲对象名显示的内容
        return f"Student('{self.name}', {self.age}, {self.score})"

s = Student("小明", 18, 95)
print(s)          # 学生:小明(18岁,成绩95分)
s                 # 在交互环境里显示 Student('小明', 18, 95)

转数字:实现 __int____float__

python 复制代码
class Score:
    def __init__(self, value):
        self.value = value
    
    def __int__(self):
        return int(self.value)
    
    def __float__(self):
        return float(self.value)

s = Score(95.7)
print(int(s))     # 95
print(float(s))   # 95.7

转字典(最常用,存数据库或转JSON):

python 复制代码
class Student:
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score
    
    def to_dict(self):
        return {
            "name": self.name,
            "age": self.age,
            "score": self.score
        }

s = Student("小明", 18, 95)
import json
print(json.dumps(s.to_dict()))   # {"name": "小明", "age": 18, "score": 95}

更高级的:用 @property 实现动态转换

python 复制代码
class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius
    
    @property
    def fahrenheit(self):
        return self._celsius * 9/5 + 32
    
    @property
    def kelvin(self):
        return self._celsius + 273.15

t = Temperature(25)
print(t.fahrenheit)   # 77.0
print(t.kelvin)       # 298.15

⑦ 典型报错信息分析与快速排错方案

转换报错是新手遇到最多的,把常见报错直接贴出来,以后碰到了对照着查。

TypeError 系列:

python 复制代码
# 不能直接把字符串和数字拼在一起
"年龄:" + 18
# TypeError: can only concatenate str (not "int") to str
# 修:f"年龄:{18}" 或 "年龄:" + str(18)

# 列表当字典的键
d = {}
d[[1,2]] = "value"
# TypeError: unhashable type: 'list'
# 修:用元组 d[(1,2)] = "value"

ValueError 系列(转数字最常见):

python 复制代码
int("12.3")      # 报错,整数不能解析带小数点的
# ValueError: invalid literal for int() with base 10: '12.3'
# 修:先转 float 再转 int,或直接用 float("12.3")

int("123abc")    # 报错
# ValueError: invalid literal...
# 修:用 re.findall(r'\d+', s) 提取数字部分

float("")        # 报错
# 修:先判断 if s: 再转换

AttributeError 系列:

python 复制代码
None.strip()     # 报错,None没有strip方法
# AttributeError: 'NoneType' object has no attribute 'strip'
# 修:检查变量为什么是None,或加上 if obj is not None:

123.split(",")   # 报错,数字没有split方法
# AttributeError: 'int' object has no attribute 'split'
# 修:先 str(123).split(",")

KeyError 和 IndexError:

python 复制代码
d = {"name": "小明"}
d["age"]         # KeyError,没有age这个键
# 修:用 d.get("age") 返回None,或 d.get("age", 默认值)

lst = [1,2,3]
lst[10]          # IndexError,下标超了
# 修:先检查 if len(lst) > 10

快速排查三连问:

  1. 这变量现在到底是什么类型?→ print(type(变量))
  2. 它现在的值是什么?→ print(repr(变量)) (repr能看到空格换行等不可见字符)
  3. 它有没有我想调的那个方法?→ print(dir(变量))

⑧ 数据清洗中的批量转换实用案例

真实数据处理里,你面对的往往是几千几万条数据,不可能一条条去转。

案例一:从CSV读取数据,转换类型

假设有个 sales.csv 文件内容如下:

yaml 复制代码
日期,产品,单价,数量
2024-01-01,苹果,5.5,100
2024-01-02,香蕉,3.2,200
2024-01-03,橙子,4.8,150
python 复制代码
import csv

def load_sales(filename):
    sales = []
    with open(filename, 'r', encoding='utf-8') as f:
        reader = csv.DictReader(f)
        for row in reader:
            # 批量转换:单价→浮点,数量→整数
            sales.append({
                "日期": row["日期"],
                "产品": row["产品"],
                "单价": float(row["单价"]),
                "数量": int(row["数量"]),
                "总额": float(row["单价"]) * int(row["数量"])
            })
    return sales

data = load_sales("sales.csv")
print(data[0])   # {'日期': '2024-01-01', '产品': '苹果', '单价': 5.5, '数量': 100, '总额': 550.0}

案例二:批量转换带脏数据的列表

python 复制代码
# 从网页或Excel粘过来的数据,经常混着各种乱七八糟的东西
raw_data = ["123", "456.7", "N/A", "789", "0", "-3.14", "  1,000  "]

def clean_number(s):
    """批量清洗转浮点数"""
    if not s or str(s).strip() == "":
        return 0.0
    s = str(s).strip()
    # 去掉千分位逗号
    s = s.replace(",", "")
    # 处理 N/A、null、None 等
    if s.upper() in ("N/A", "NULL", "NONE", "-", "--"):
        return 0.0
    try:
        return float(s)
    except ValueError:
        # 尝试提取第一个数字
        import re
        match = re.search(r'[-+]?\d*\.?\d+', s)
        return float(match.group()) if match else 0.0

cleaned = [clean_number(x) for x in raw_data]
print(cleaned)   # [123.0, 456.7, 0.0, 789.0, 0.0, -3.14, 1000.0]

案例三:字典列表的字段类型统一

python 复制代码
users = [
    {"id": "1", "name": "张三", "age": "25", "active": "true"},
    {"id": "2", "name": "李四", "age": "三十", "active": "false"},
    {"id": "3", "name": "王五", "age": "28", "active": "True"},
]

def normalize_user(u):
    return {
        "id": int(u["id"]) if u["id"].isdigit() else 0,
        "name": u["name"].strip(),
        "age": int(u["age"]) if u["age"].isdigit() else None,
        "active": u["active"].lower() in ("true", "1", "yes")
    }

normalized = [normalize_user(u) for u in users]
print(normalized)
# [{'id': 1, 'name': '张三', 'age': 25, 'active': True}, ...]

⑨ 提升代码健壮性的类型检查习惯

写代码防不住所有意外,但能防住大部分。下面几个习惯帮你少熬夜。

习惯一:进门先检查类型

python 复制代码
def process_scores(scores):
    # 进来先确认类型
    if not isinstance(scores, (list, tuple)):
        raise TypeError("scores 必须是列表或元组")
    
    # 再检查每个元素
    for s in scores:
        if not isinstance(s, (int, float)):
            raise ValueError(f"分数必须为数字,但遇到了 {s}")
    
    return sum(scores) / len(scores)

习惯二:用 try/except 兜底(比 if 更Pythonic)

python 复制代码
# 不推荐:先检查再转换
if isinstance(s, str) and s.isdigit():
    num = int(s)
else:
    num = 0

# 推荐:直接转,出错再处理(EAFP原则:请求原谅比请求许可更容易)
try:
    num = int(s)
except (ValueError, TypeError):
    num = 0

习惯三:写类型注解(Python 3.5+)

python 复制代码
from typing import Optional, Union, List, Dict

def parse_user_data(
    raw_data: Dict[str, str],
    default_age: int = 18
) -> Optional[Dict[str, Union[str, int]]]:
    """
    参数类型和返回值类型一目了然
    但不强制,只是给人看的
    """
    try:
        return {
            "name": raw_data.get("name", "").strip(),
            "age": int(raw_data.get("age", default_age))
        }
    except ValueError:
        return None

习惯四:写防御性的一行转换工具

python 复制代码
def to_str(obj, default=""):
    return str(obj) if obj is not None else default

def to_int(obj, default=0):
    try:
        return int(obj)
    except (ValueError, TypeError):
        return default

def to_float(obj, default=0.0):
    try:
        return float(obj)
    except (ValueError, TypeError):
        return default

def to_bool(obj, default=False):
    if isinstance(obj, bool):
        return obj
    if isinstance(obj, str):
        return obj.lower() in ("true", "1", "yes", "on")
    if isinstance(obj, (int, float)):
        return bool(obj)
    return default

⑩ 综合演练:构建简易数据格式化工具

把上面所有东西拼起来,做一个能把各种乱七八糟输入统一转换成标准格式的小工具。

python 复制代码
"""
简易数据格式化器
功能:接收用户输入的一行数据,自动识别类型并转换成标准格式输出
"""

import re
from typing import Any, Optional

class DataFormatter:
    """数据格式化器 - 自动识别并转换类型"""
    
    def __init__(self):
        self.errors = []  # 记录转换过程中的错误
    
    def detect_and_convert(self, raw: str) -> Optional[Any]:
        """
        检测字符串类型并转换
        优先级:数字 → 布尔 → 日期 → 字符串
        """
        if raw is None:
            return None
        
        s = raw.strip()
        if s == "":
            return None
        
        # 1. 尝试转数字(整数优先)
        num_result = self._try_number(s)
        if num_result is not None:
            return num_result
        
        # 2. 尝试转布尔
        bool_result = self._try_boolean(s)
        if bool_result is not None:
            return bool_result
        
        # 3. 默认返回字符串(去除首尾空白)
        return s
    
    def _try_number(self, s: str) -> Optional[Any]:
        """尝试转数字,支持千分位、正负号、科学计数法"""
        # 去除千分位逗号
        cleaned = s.replace(",", "")
        # 处理科学计数法 1.23e-4
        if re.match(r'^[-+]?\d+\.?\d*[eE][-+]?\d+$', cleaned):
            try:
                return float(cleaned)
            except ValueError:
                pass
        
        # 尝试整数
        try:
            return int(cleaned)
        except ValueError:
            pass
        
        # 尝试浮点数
        try:
            return float(cleaned)
        except ValueError:
            pass
        
        return None
    
    def _try_boolean(self, s: str) -> Optional[bool]:
        """尝试转布尔值"""
        true_values = {"true", "yes", "是", "对", "1", "on", "enabled", "enable"}
        false_values = {"false", "no", "否", "错", "0", "off", "disabled", "disable"}
        
        lower = s.lower()
        if lower in true_values:
            return True
        if lower in false_values:
            return False
        return None
    
    def format_row(self, *args) -> list:
        """格式化一行数据,每个字段独立转换"""
        result = []
        self.errors = []
        for i, arg in enumerate(args):
            try:
                converted = self.detect_and_convert(arg)
                result.append(converted)
            except Exception as e:
                self.errors.append(f"字段{i}转换失败: {e}")
                result.append(None)
        return result
    
    def format_table(self, rows: list) -> list:
        """批量格式化多行数据"""
        return [self.format_row(*row) for row in rows]
    
    def to_csv_line(self, row: list, delimiter: str = ",") -> str:
        """把格式化的行转成CSV行"""
        return delimiter.join(str(v) if v is not None else "" for v in row)


# ---------- 实战测试 ----------
if __name__ == "__main__":
    formatter = DataFormatter()
    
    # 模拟从用户输入或Excel读取的原始数据
    raw_rows = [
        ["1", "张三", "25", "true", "3.14"],
        ["2", "李四", "三十", "false", "2.718"],
        ["3", "王五", "28", "是", "1,234.56"],
        ["4", "", "", "yes", ""],
    ]
    
    print("原始数据:")
    for row in raw_rows:
        print(row)
    
    print("\n格式化后:")
    formatted = formatter.format_table(raw_rows)
    for row in formatted:
        print(row)
    
    print("\n转成CSV输出:")
    for row in formatted:
        print(formatter.to_csv_line(row))
    
    if formatter.errors:
        print(f"\n转换过程中有 {len(formatter.errors)} 个错误:")
        for err in formatter.errors:
            print(f"  - {err}")

运行效果(预期输出):

python 复制代码
原始数据:
['1', '张三', '25', 'true', '3.14']
['2', '李四', '三十', 'false', '2.718']
['3', '王五', '28', '是', '1,234.56']
['4', '', '', 'yes', '']

格式化后:
[1, '张三', 25, True, 3.14]
[2, '李四', None, False, 2.718]
[3, '王五', 28, True, 1234.56]
[4, '', None, True, None]

转成CSV输出:
1,张三,25,True,3.14
2,李四,,False,2.718
3,王五,28,True,1234.56
4,,,True,

你自己动手改一改:

  1. 把年龄"三十"这种中文数字也转成整数(提示:建个字典映射)
  2. 增加对日期格式 2024-01-01 的识别
  3. 增加一个选项,让数字默认转成整数还是浮点数

这个工具虽然简单,但实际工作中处理 Excel、CSV、用户表单数据时,核心思路完全一样------先识别,再转换,出错兜底。把这个跑通了,Python类型转换这块就算真正拿下了。

相关推荐
苏三说技术16 小时前
为什么Spring要“抛弃”Feign?
后端
神奇小汤圆17 小时前
Java代理模式深度解析:静态代理 vs 动态代理 vs CGLIB
后端
爱勇宝17 小时前
AI不会淘汰所有人,但会淘汰这6种人
前端·后端·程序员
Conan在掘金17 小时前
鸿蒙 ArkUI 进阶:@Extend 和 @Styles,把样式也抽成「乐高块」的正确姿势
后端
orient17 小时前
为什么需要并发编程
后端
Cosolar17 小时前
AI Agent 架构原理详解:从一次提问到任务完成的完整闭环
人工智能·后端·架构
Conan在掘金17 小时前
鸿蒙 ArkUI 深水区:Stage 模型多维状态,从「组件内」跳到「应用级」的分水岭
后端
长栎18 小时前
用AI优化Redis缓存失效,我把热key问题想简单了
后端
面试鸭18 小时前
我说我们做 Agent 从来不怕死循环,面试官调出兜底日志:“第 47 次强制终止,是你半夜爬起来按停的?”
后端·面试·求职