YAML 从入门到应用:轻松搞定配置管理与数据序列化

YAML 从入门到应用:轻松搞定配置管理与数据序列化

YAML 从入门到应用:轻松搞定配置管理与数据序列化咱们先唠唠,你是不是也遇到过这种情况:写 Python 项目时,想把配置(比如数据库地址、参数设置)和代码分开,不然每次改配置都要动代码,太麻烦了;或者想存点结构化数据,JSON 虽然能用,但写注释、处理多行文本总觉得别扭?

这时候 YAML 就派上用场了!今天咱们就从 0 开始,把 Python 里用 YAML 的那点事儿讲透,不管你是新手还是有点经验,看完都能直接上手用。

1. 认识 YAML:到底是个啥?有啥优点?先搞明白基础:YAML 不是什么高深技术,就是一种 “人类能轻松看懂” 的数据序列化语言。简单说,就是把 Python 里的字典、列表这些数据,写成文件存起来;反过来,也能把文件里的内容读成 Python 能直接用的数据。

它的优点特别实在,咱们列个表更清楚:

优点

大白话解释

简单易读

不用写大括号、中括号(比如 JSON 的 {}[]),靠缩进就能表示结构,像写笔记一样

语言支持广

不光 Python 能用,Java、Go、JavaScript 都支持,跨语言传数据方便

支持多种数据类型

字符串、数字、布尔值这些基础类型,还有字典、列表,甚至嵌套结构都能搞定

能加注释

用 #开头写注释,以后看自己写的配置,一眼就知道啥意思

适合配置和数据存储

存配置文件(比如项目参数)、数据文件(比如翻译内容)都特别合适

2. 准备工作:先装个 pyyaml 库Python 本身不自带处理 YAML 的工具,得装个第三方库叫pyyaml,跟装其他库一样简单,就用pip命令。

安装步骤(保证能运行):打开你的命令行(Windows 是 CMD 或 PowerShell,Mac/Linux 是终端)直接输下面这个命令,按回车:代码语言:python复制pip install pyyaml等个几秒钟,看到 “Successfully installed pyyaml-x.x.x”(x.x.x 是版本号)就装好了。常见安装问题:要是提示 “权限不够”(比如 Linux/Mac),就在命令前面加sudo:代码语言:python复制sudo pip install pyyaml要是提示 “pip 不是内部命令”,那是你 Python 没配置环境变量,或者直接用python -m pip代替pip:代码语言:python复制python -m pip install pyyaml3. 第一步:创建你的第一个 YAML 文件YAML 文件的后缀一般是.yaml(推荐)或者.yml,随便用个文本编辑器就能写(比如记事本、VSCode、Sublime)。

咱们先写个最简单的,叫first.yaml,内容如下:

代码语言:python复制# 这是注释,#后面的内容不会被解析

name: 张三 # 键是name,值是字符串“张三”

age: 25 # 键是age,值是整数25

is_student: false # 键是is_student,值是布尔值false

score: 98.5 # 键是score,值是浮点数98.5

hobbies: # 键是hobbies,值是列表(用-开头表示列表元素)

- 篮球

- 编程

- 看电影

address: # 键是address,值是字典(嵌套结构,靠缩进)

province: 广东

city: 深圳

detail: 某小区12栋注意两个关键规则(刚开始容易错):

缩进敏感:YAML 靠缩进来表示层级,必须用空格,不能用 Tab!一般缩进 2 个或 4 个空格(推荐 2 个,统一就行)。键值对格式:键和值之间必须用冒号 + 空格(比如name: 张三,冒号后没空格会报错)。4. 第二步:把 YAML 文件加载到 Python 里写好 YAML 文件后,怎么在 Python 里读它呢?就用刚装的pyyaml库,步骤特别固定,咱们写个 Python 脚本load_yaml.py:

代码示例(保证能运行):代码语言:python复制import yaml # 导入pyyaml库

# 方法1:读取外部YAML文件(最常用)

def load_yaml_file(file_path):

try:

# 用open打开文件,指定编码utf-8(避免中文乱码)

with open(file_path, 'r', encoding='utf-8') as f:

# 用safe_load加载,重点:别用load!后面讲为什么

data = yaml.safe_load(f)

return data

except FileNotFoundError:

print(f"报错:没找到{file_path}这个文件!")

return None

except Exception as e:

print(f"加载YAML出错了:{e}")

return None

# 调用函数,加载咱们刚才写的first.yaml

yaml_data = load_yaml_file("first.yaml")

# 打印结果,看看是不是Python能直接用的数据

if yaml_data:

print("加载出来的Python数据:")

print(yaml_data)

print("n单独取某个值:")

print(f"名字:{yaml_data['name']}")

print(f"年龄:{yaml_data['age']}")

print(f"第一个爱好:{yaml_data['hobbies'][0]}")

print(f"城市:{yaml_data['address']['city']}")怎么运行:把first.yaml和load_yaml.py放在同一个文件夹里命令行进入这个文件夹,输:代码语言:python复制python load_yaml.py运行结果:你会看到这样的输出,说明 YAML 里的数据已经变成 Python 的字典、列表了:

代码语言:python复制加载出来的Python数据:

{'name': '张三', 'age': 25, 'is_student': False, 'score': 98.5, 'hobbies': ['篮球', '编程', '看电影'], 'address': {'province': '广东', 'city': '深圳', 'detail': '某小区12栋'}}

单独取某个值:

名字:张三

年龄:25

第一个爱好:篮球

城市:深圳5. YAML 数据类型:从简单到复杂(必掌握)YAML 支持的所有数据类型,咱们用表格整理清楚,每个类型都给 YAML 写法和对应的 Python 结果,看完直接能套用。

5.1 基础数据类型数据类型

YAML 写法示例

Python 对应类型

Python 加载结果

注意事项

字符串

name: 张三name: "张三"name: ' 张三'

str

' 张三'

一般不用引号,有特殊字符(比如空格、#)才用

整数

age: 25count: -10

int

25-10

直接写数字,不用加引号

浮点数

score: 98.5pi: 3.14e2

float

98.5314.0

支持科学计数法(3.14e2=314)

布尔值

is_ok: trueis_no: false

bool

TrueFalse

不区分大小写(TRUE 也可以),但推荐小写

Null 值

empty: ~none_val: null

None

None

~ 或 null 都表示空,Python 里是 None

5.2 复杂数据类型(字典、列表)这俩是最常用的,尤其是嵌套结构,咱们分开讲:

(1)字典(键值对集合)YAML 里的字典就是 “键:值” 的组合,嵌套字典靠缩进:

代码语言:python复制# YAML写法

person:

name: 李四

age: 30

contact: # 嵌套字典

phone: 13800138000

email: lisi@example.com加载到 Python 后是这样的字典:

代码语言:python复制{'person': {'name': '李四', 'age': 30, 'contact': {'phone': '13800138000', 'email': 'lisi@example.com'}}}(2)列表(有序元素集合)YAML 里的列表用-开头,每个-代表一个元素,嵌套列表也靠缩进:

代码语言:python复制# YAML写法

fruits: # 普通列表

- 苹果

- 香蕉

- 橙子

students: # 嵌套列表(列表里套字典)

- name: 王五

age: 22

- name: 赵六

age: 23加载到 Python 后是这样的:

代码语言:python复制{'fruits': ['苹果', '香蕉', '橙子'], 'students': [{'name': '王五', 'age': 22}, {'name': '赵六', 'age': 23}]}5.3 测试代码(验证数据类型)写个test_types.yaml,把上面的类型都放进去:

代码语言:python复制# 基础类型

string_val: 测试字符串

int_val: 100

float_val: 3.14

bool_val: true

null_val: ~

# 复杂类型

dict_val:

key1: val1

key2: val2

list_val:

- 元素1

- 元素2

nested_val: # 嵌套(字典里套列表)

class: 三年级1班

students:

- 小明

- 小红再写个test_types.py加载它:

代码语言:python复制import yaml

with open("test_types.yaml", 'r', encoding='utf-8') as f:

data = yaml.safe_load(f)

# 打印每个值的类型和内容

print("string_val:", type(data['string_val']), "->", data['string_val'])

print("int_val:", type(data['int_val']), "->", data['int_val'])

print("float_val:", type(data['float_val']), "->", data['float_val'])

print("bool_val:", type(data['bool_val']), "->", data['bool_val'])

print("null_val:", type(data['null_val']), "->", data['null_val'])

print("dict_val:", type(data['dict_val']), "->", data['dict_val'])

print("list_val:", type(data['list_val']), "->", data['list_val'])

print("nested_val:", type(data['nested_val']), "->", data['nested_val'])运行后会看到每个值的类型,确认 YAML 和 Python 类型是对应的,比如bool_val是bool类型,dict_val是dict类型。

6. YAML 特色功能:这些技巧超实用!YAML 有几个特别好用的功能,学会了能省很多事,咱们一个个讲,每个都给示例。

6.1 加注释:让别人看懂你的配置这个简单,用#开头,后面的内容都是注释,YAML 解析的时候会忽略:

代码语言:python复制# 这是一个项目配置文件

# 作者:XXX

# 日期:不用写死,运行时Python能获取

# 数据库配置

db:

host: localhost # 数据库地址,本地测试用localhost

port: 3306 # MySQL默认端口

user: root # 用户名,生产环境别用root!

password: 123456 # 密码,实际项目要存在环境变量里,别写这注意:注释只能写在单独一行,或者键值对的后面,不能插在键和值中间(比如name: # 注释 张三这样会报错)。

6.2 多行字符串:处理大段文本(管道符 | vs 折叠符 >)有时候要存大段文本(比如日志模板、邮件内容),用字符串写一行太别扭,YAML 的多行字符串就很方便,关键是区分|(管道符)和>(折叠符)。

两者的区别(重点):|:保留所有换行和空格,写的时候是什么样,加载后就是什么样。>:把换行变成空格(除了最后一个换行),适合存一段连续的文本,不想换行。示例:写个multi_line.yaml代码语言:python复制# 管道符|:保留换行

text_with_newline: |

第一行文本

第二行文本(前面有2个空格)

第三行文本(前面有4个空格)

第四行文本

# 折叠符>:换行变空格

text_no_newline: >

这是一段很长的文本,

本来写了换行,

但用了折叠符后,

会变成一整行(最后会留一个换行)加载代码load_multi_line.py:代码语言:python复制import yaml

with open("multi_line.yaml", 'r', encoding='utf-8') as f:

data = yaml.safe_load(f)

print("=== 管道符|的结果(保留换行)===")

print(data['text_with_newline'])

print("=== 折叠符>的结果(换行变空格)===")

print(data['text_no_newline'])运行结果:你会明显看到区别:

代码语言:python复制=== 管道符|的结果(保留换行)===

第一行文本

第二行文本(前面有2个空格)

第三行文本(前面有4个空格)

第四行文本

=== 折叠符>的结果(换行变空格)===

这是一段很长的文本, 本来写了换行, 但用了折叠符后, 会变成一整行(最后会留一个换行)注意:多行字符串的缩进要跟父元素的缩进一致(比如上面text_with_newline下面的文本,缩进都是 2 个空格,跟text_with_newline的键对齐),不然会解析错。

6.3 锚点和别名:实现数据重用(避免重复写)如果 YAML 里有重复的数据(比如多个用户用同一个地址),不用每次都写一遍,用锚点(&) 标记重复数据,再用别名(*) 引用,省事又不容易错。

示例 1:简单引用(anchor1.yaml)代码语言:python复制# 用&定义锚点(anchor_address是锚点名字,随便起)

address: &anchor_address

province: 浙江

city: 杭州

street: 西湖路

# 用*引用锚点

user1:

name: 小明

addr: *anchor_address # 引用上面的address

user2:

name: 小红

addr: *anchor_address # 再引用一次加载结果:代码语言:python复制{'address': {'province': '浙江', 'city': '杭州', 'street': '西湖路'},

'user1': {'name': '小明', 'addr': {'province': '浙江', 'city': '杭州', 'street': '西湖路'}},

'user2': {'name': '小红', 'addr': {'province': '浙江', 'city': '杭州', 'street': '西湖路'}}}示例 2:合并字典(用 <<)如果想在引用的基础上改点数据(比如 user2 的街道不一样),可以用<<把锚点的字典合并进来,再覆盖需要改的键:

代码语言:python复制address: &anchor_address

province: 浙江

city: 杭州

street: 西湖路

user1:

name: 小明

<<: *anchor_address # 合并锚点的字典,相当于把province、city、street直接写在这里

user2:

name: 小红

<<: *anchor_address # 先合并

street: 钱江路 # 覆盖street的值加载结果:代码语言:python复制{'address': {'province': '浙江', 'city': '杭州', 'street': '西湖路'},

'user1': {'name': '小明', 'province': '浙江', 'city': '杭州', 'street': '西湖路'},

'user2': {'name': '小红', 'province': '浙江', 'city': '杭州', 'street': '钱江路'}}看,user2 的 street 变成了 “钱江路”,其他字段还是锚点里的,特别方便!

6.4 紧凑写法:字典用 {},列表用 [](简单数据专用)如果数据很简单,不想用缩进占太多行,可以用紧凑写法:字典用{}包起来,列表用[]包起来,跟 JSON 有点像,但 YAML 支持的更多。

示例(compact.yaml):代码语言:python复制# 紧凑字典:用{}

person: {name: 小李, age: 28, is_student: false}

# 紧凑列表:用[]

fruits: [苹果, 香蕉, 橙子]

# 混合紧凑:列表里套字典

students: [{name: 小王, age: 20}, {name: 小刘, age: 21}]加载结果:跟普通写法完全一样,就是写起来更短:

代码语言:python复制{'person': {'name': '小李', 'age': 28, 'is_student': False},

'fruits': ['苹果', '香蕉', '橙子'],

'students': [{'name': '小王', 'age': 20}, {'name': '小刘', 'age': 21}]}注意:紧凑写法只适合简单数据,复杂的嵌套还是用缩进写法,不然会乱。

7. 安全第一:别用 yaml.load ()!前面加载 YAML 的时候,我一直用yaml.safe_load(),没提yaml.load(),不是忘了,是yaml.load()有大风险!

为什么危险?yaml.load()默认会用一个叫Loader的解析器,这个解析器能执行 Python 代码!如果加载的 YAML 文件里有恶意代码(比如删除你电脑文件的命令),就会直接运行,后果很严重。

举个恐怖的例子:如果有人给你一个malicious.yaml,内容是这样的:

代码语言:python复制!!python/object/apply:os.system ["rm -rf /"]你要是用yaml.load()加载:

代码语言:python复制import yaml

with open("malicious.yaml", 'r') as f:

yaml.load(f) # 危险!会执行rm -rf /(删除Linux所有文件)在 Linux/Mac 上运行,你的文件就全没了!Windows 上虽然命令不生效,但也可能执行其他恶意操作。

正确的做法(必记):不管什么时候,都用yaml.safe_load(),或者指定yaml.SafeLoader:

代码语言:python复制# 方法1:推荐,简单

data = yaml.safe_load(f)

# 方法2:等价于safe_load,更明确

data = yaml.load(f, Loader=yaml.SafeLoader)safe_load()只会解析 YAML 的基础数据类型(字典、列表、字符串等),不会执行任何 Python 代码,绝对安全。

8. 实际应用:加载多语言翻译文件讲了这么多理论,咱们来个实际项目里常用的场景:多语言支持。比如你的程序要支持中文和英文,把翻译内容存在 YAML 里,用户选哪个语言就加载哪个文件,不用改代码。

步骤 1:创建翻译文件先建两个 YAML 文件,分别存中文和英文的翻译:

zh.yaml(中文翻译):代码语言:python复制welcome: "欢迎使用本程序!"

select_lang: "请选择语言(zh=中文,en=英文):"

input_error: "输入错误,请重新输入!"

exit_msg: "程序已退出,再见!"en.yaml(英文翻译):代码语言:python复制welcome: "Welcome to the program!"

select_lang: "Please select language (zh=Chinese, en=English): "

input_error: "Input error, please try again!"

exit_msg: "Program exited, goodbye!"步骤 2:写 Python 脚本加载翻译创建multi_lang.py,功能是:

提示用户选择语言加载对应的 YAML 翻译文件用翻译内容和用户交互代码(保证能运行):代码语言:python复制import yaml

def load_translation(lang):

"""加载对应语言的翻译文件"""

# 定义语言和文件名的对应关系

lang_files = {

'zh': 'zh.yaml',

'en': 'en.yaml'

}

# 检查语言是否支持

if lang not in lang_files:

return None

# 加载YAML文件

try:

with open(lang_files[lang], 'r', encoding='utf-8') as f:

return yaml.safe_load(f)

except Exception as e:

print(f"加载翻译文件失败:{e}")

return None

def main():

# 先提示选择语言(默认中文)

default_lang = 'zh'

print(f"默认语言是中文,如需英文请输入'en'")

user_lang = input("请输入语言(zh/en):").strip().lower() or default_lang

# 加载翻译

trans = load_translation(user_lang)

if not trans:

print("不支持的语言,使用默认中文!")

trans = load_translation('zh')

# 用翻译内容和用户交互

print("n" + trans['welcome'])

# 这里可以加其他功能,比如显示菜单

input("n按回车键退出...")

print(trans['exit_msg'])

if __name__ == "__main__":

main()怎么运行:把zh.yaml、en.yaml、multi_lang.py放同一个文件夹运行multi_lang.py,输入zh或en试试运行示例(输入 en):代码语言:python复制默认语言是中文,如需英文请输入'en'

请输入语言(zh/en):en

Welcome to the program!

按回车键退出...

Program exited, goodbye!这个场景的好处是:以后要加日语、法语,只需要新建jp.yaml、fr.yaml,不用改 Python 代码,维护起来特别方便。

9. 踩坑指南:常见问题 & 错误解决刚开始用 YAML,很容易踩坑,我整理了几个最常见的问题,告诉你怎么解决。

9.1 缩进错误(最常见!)错误现象:加载时报错yaml.scanner.ScannerError: mapping values are not allowed here,或者expected , but found ''。

错误原因:混用了 Tab 和空格(YAML 只认空格)缩进级别不一致(比如有的地方缩 2 个空格,有的缩 4 个)错误示例:代码语言:python复制# 错误:address下面的province用了Tab缩进,其他用空格

person:

name: 张三

address:

province: 广东 # 这里是Tab,错了!

city: 深圳 # 这里是2个空格解决方法:所有缩进都用空格(推荐 2 个)用文本编辑器开启 “显示空格” 功能(VSCode 按 Ctrl+Shift+P,输 “Toggle Render Whitespace”),能看到是不是混用了 Tab。9.2 键值对格式错误错误现象:报错yaml.parser.ParserError: expected ':'。

错误原因:键和值之间没加空格(比如name:张三,少了空格)漏了冒号(比如name 张三)错误示例:代码语言:python复制# 错误1:冒号后没空格

name:张三

age:25

# 错误2:漏了冒号

name 张三解决方法:严格遵守 “键:值” 格式,冒号后必须加一个空格。

9.3 布尔值和字符串混淆错误现象:YAML 里写的 “yes”,加载后变成了 Python 的True,不是字符串。

原因:YAML 会把yes/no/true/false这些词解析成布尔值,如果你想让它们是字符串,必须加引号。

示例:代码语言:python复制# 会被解析成布尔值True

is_ok: yes

# 正确:加引号,解析成字符串"yes"

is_ok_str: "yes"9.4 中文乱码错误现象:加载 YAML 后,中文显示成乱码(比如'xe5xbcxa0xe4xb8x89')。

原因:open 文件时没指定编码encoding='utf-8'。

解决方法:打开文件时一定要加encoding='utf-8':

代码语言:python复制with open("first.yaml", 'r', encoding='utf-8') as f: # 加encoding

data = yaml.safe_load(f)10. 面试必看:YAML 常见问题 & 回答如果面试 Python 相关岗位,可能会被问到 YAML,这些问题和回答记下来,够用了。

问题 1:YAML 是什么?它有什么优点?回答:YAML 是一种人类可读的数据序列化语言,主要用来存配置文件或结构化数据。优点有:

易读性高,靠缩进表示结构,不用写大括号中括号;支持注释,方便维护;支持多种数据类型,包括基础类型和嵌套的字典、列表;跨语言支持好,Python、Java 这些都能用;适合做配置管理,比如项目参数、多语言翻译。问题 2:Python 中处理 YAML 需要什么库?怎么加载 YAML 文件?回答:需要第三方库pyyaml,先装pip install pyyaml。加载文件用yaml.safe_load(),步骤是:

用open(file_path, 'r', encoding='utf-8')打开文件;用yaml.safe_load(f)加载内容,得到 Python 的字典或列表;注意不能用yaml.load(),因为它不安全,可能执行恶意代码。问题 3:YAML 中的管道符(|)和折叠符(>)有什么区别?回答:都是用来处理多行字符串的,区别在换行的处理:

管道符|:会保留所有换行和空格,写的时候是什么格式,加载后就是什么格式;折叠符>:会把换行转换成空格(最后一个换行保留),适合存连续的文本,不想换行。问题 4:YAML 怎么实现数据重用?回答:用锚点和别名:

用&锚点名定义要重用的数据(比如address: &addr {province: 北京});用*锚点名引用数据(比如user: {name: 张三, addr: *addr});如果想在引用的基础上改数据,可以用<<合并锚点字典,再覆盖键(比如user: {<<: *addr, city: 朝阳})。问题 5:为什么不推荐用 yaml.load ()?生产环境应该用什么?回答:因为yaml.load()默认用Loader解析器,这个解析器能执行 Python 代码,如果加载的 YAML 有恶意代码(比如执行系统命令),会造成安全风险。生产环境必须用yaml.safe_load(),它只会解析基础数据类型,不会执行任何代码,更安全。

问题 6:YAML 和 JSON 有什么区别?什么时候用 YAML,什么时候用 JSON?回答:区别主要在可读性和功能:

可读性:YAML 靠缩进,支持注释,更易读;JSON 靠 {}[],不支持注释,机器解析快但人看费劲;功能:YAML 支持锚点、多行字符串;JSON 不支持;兼容性:JSON 是 YAML 的子集,所有 JSON 文件都能被 YAML 解析,但反过来不行。使用场景:

存配置文件(比如项目参数、多语言):用 YAML,方便维护;接口传输数据(比如前后端交互):用 JSON,因为跨语言兼容性更好,解析速度快。11. 总结:YAML 能帮你做什么?看到这里,你应该明白 YAML 的核心价值了:把数据和代码分开,让配置更灵活、维护更简单。

比如:

项目里的数据库配置、API 地址,不用写在代码里,存在 YAML 里,改配置不用动代码;多语言项目,把翻译内容存在不同的 YAML 文件里,切换语言只需要加载不同文件;测试数据用 YAML 存,写测试用例时直接加载,不用硬编码。YAML 不难,重点是记住缩进规则、安全加载,再掌握锚点、多行字符串这些实用功能,就能轻松搞定 Python 里的配置管理和数据序列化了。

赶紧动手试试吧!把上面的示例代码跑一遍,遇到问题对照 “踩坑指南” 解决,很快就能上手。

猜你喜欢 💖

苹果手机数据同步方法与技巧:iCloud、iTunes及更多实用功能解析
深宫计粤语
beat365官方网址

深宫计粤语

📅 07-11 👁️ 2558
昨日触板概念股涨幅0.79%,大众交通和中毅达领涨背后暗藏哪些机遇?