Python3 数据类型转换新手实战指南
别被"数据类型转换"这个名词唬住------说白了就是"把一种格式的数据变成另一种格式"。你平时把Excel表格另存为CSV,把Word转成PDF,干的也是同样的事。
① 常见数据类型特征与转换场景解析
先快速过一遍 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
快速排查三连问:
- 这变量现在到底是什么类型?→
print(type(变量)) - 它现在的值是什么?→
print(repr(变量))(repr能看到空格换行等不可见字符) - 它有没有我想调的那个方法?→
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,
你自己动手改一改:
- 把年龄"三十"这种中文数字也转成整数(提示:建个字典映射)
- 增加对日期格式
2024-01-01的识别 - 增加一个选项,让数字默认转成整数还是浮点数
这个工具虽然简单,但实际工作中处理 Excel、CSV、用户表单数据时,核心思路完全一样------先识别,再转换,出错兜底。把这个跑通了,Python类型转换这块就算真正拿下了。