python-第三方库-[yarl、yaml]
- [一: yarl](#一: yarl)
-
- [1> yarl 介绍](#1> yarl 介绍)
- [2> yarl.URL 介绍](#2> yarl.URL 介绍)
-
- [1. yarl.URL 的语法格式](#1. yarl.URL 的语法格式)
- [2. yarl.URL demo](#2. yarl.URL demo)
- [3. yarl.URL.build()](#3. yarl.URL.build())
- [4. yarl.URL().with_*()](#4. yarl.URL().with_*())
- [5. yarl.URL().update_query()](#5. yarl.URL().update_query())
- [6> url / &%组合](#6> url / &%组合)
- 二:yaml
-
- [1> yaml 介绍](#1> yaml 介绍)
- [2> yaml 基本规则](#2> yaml 基本规则)
-
- [1. 数据结构介绍](#1. 数据结构介绍)
-
- 普通样式、单/双引号样式
- [字面样式(literal )](#字面样式(literal ))
- 折叠样式(folded)
- Mappings(映射)
- [2. 语法锚点和引用](#2. 语法锚点和引用)
- [3. yaml tag](#3. yaml tag)
-
- [tag 介绍](#tag 介绍)
- 自定义tag
- [3> yaml demo](#3> yaml demo)
-
- [1. yaml.load](#1. yaml.load)
- [2. yaml.load Unicode&yaml.Loader](#2. yaml.load Unicode&yaml.Loader)
- [3. yaml.dump&Unicode](#3. yaml.dump&Unicode)
- [4. yaml.load_all](#4. yaml.load_all)
- [5. yaml 与编码对象class](#5. yaml 与编码对象class)
- [6. yaml 多个编码对象class](#6. yaml 多个编码对象class)
- [7. yaml.safe_load](#7. yaml.safe_load)
- [4> yaml 三大组件](#4> yaml 三大组件)
-
-
- [1. 构造器、表示器、解析器 介绍](#1. 构造器、表示器、解析器 介绍)
- [2. 构造&转存](#2. 构造&转存)
- [3. 序列化构造器](#3. 序列化构造器)
- [4. 自定义构造器](#4. 自定义构造器)
-
- [5> yaml引用环境变量](#5> yaml引用环境变量)
- [6> libyaml](#6> libyaml)
- [7> FAQ](#7> FAQ)
-
- [1. yaml.safe_load&load区别](#1. yaml.safe_load&load区别)
一: yarl
1> yarl 介绍
URL介绍 :统一资源定位符,它是用来表示互联网上的某个资源地址,互联网上的每个文件都有一个唯一的 URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它;
yarl :yarl 库是一个强大的工具,用于处理 URL(统一资源定位符);
yarl作用:提供了简单且灵活的 API,使得 URL 的解析、构建和操作变得简单;
2> yarl.URL 介绍
from yarl import URL
1. yarl.URL 的语法格式
URL 的语法格式:
protocol://hostname[:port]/path[?query][#fragment]
part | 含义 | 注释 |
---|---|---|
protocol | 指网络传输协议 | 以下是经常用到的几个协议; http,通过 HTTP 协议访问该资源,格式 http://; https,通过安全的 HTTPS 协议访问该资源, 格式 https://; file,资源是本地计算机上的文件,格式 file:// ftp,通过 FTP访问资源,格式 FTP:// |
hostname | 主机名 | 指存放资源的服务器的域名、主机名或 IP 地址。有时,在主机名前也可以包含连接到服务器所需的用户名和密码(格式:username:password@hostname) |
port | 端口号 | port 是一个可选的整数,它的取值范围 是 0-65535。如果 port 被省略时就使用默认端口,各种传输协议都有默认的端口号,如 http 的默认端口为 80,https 的端口是 443; |
path | 路由地址 | 由零个或多个/符号隔开的字符串,一般用来表示主机上的一个目录或文件地址。路由地址决定了服务端如何处理这个请求; |
query | 查询 | 从?开始到#为止,它们之间的部分就是参数,又称搜索部分或者查询字符串。这个部分允许有多个参数,参数与参数之间用&作为分隔符;下面demo 为:spm=1011.2124.3001.5298 |
fragment | 信息片断 | 它用于指定网络资源中的片断,例如一个网页中有多个名词解释,那么可使用 fragment 直接对它们定位 |
2. yarl.URL demo
from yarl import URL
url_string = "https://mp.csdn.net/mp_blog/manage/article?spm=1011.2124.3001.5298"
url = URL(url_string)
print(url)
print(url.scheme)
print(url.host)
print(url.port)
print(url.authority)
print(url.path)
print(url.query)
print(url.query_string)
print(url.user)
print(url.password)
=======================
https://mp.csdn.net/mp_blog/manage/article?spm=1011.2124.3001.5298
https
mp.csdn.net
443
mp.csdn.net:443
/mp_blog/manage/article
<MultiDictProxy('spm': '1011.2124.3001.5298')>
spm=1011.2124.3001.5298
None
None
3. yarl.URL.build()
from yarl import URL
url = URL.build(
scheme='https',
host='mp.csdn.net',
port=443,
path='/mp_blog/manage/article',
query={'spm': '1011.2124.3001.5298'}
)
print(url)
===============
https://mp.csdn.net:443/mp_blog/manage/article?spm=1011.2124.3001.5298
4. yarl.URL().with_*()
with_scheme、with_user 、with_password 、with_host 、with_port、with_path、with_query、with_fragment、with_name
with_*() 单步骤构建
from yarl import URL
url = URL.build(
scheme='https',
host='mp.csdn.net',
port=443,
path='/mp_blog/manage/article',
)
query = {'spm': '1011.2124.3001.5298'}
print(url.with_query(query))
with_().with_()多步骤构建url
from yarl import URL
url = URL.build(
scheme='https',
host='mp.csdn.net',
port=443,
)
print(url)
query = {'spm': '1011.2124.3001.5298'}
print(url.with_path('/mp_blog/manage/article').with_query(query))
============================
https://mp.csdn.net:443
https://mp.csdn.net:443/mp_blog/manage/article?spm=1011.2124.3001.5298
5. yarl.URL().update_query()
url.with_query(query):清除之前的query 信息;
from yarl import URL
url = URL.build(
scheme='https',
host='mp.csdn.net',
port=443,
path='/mp_blog/manage/article',
query = {'spm': '1011.2124.3001.5298'}
)
query = {'xxx': '127.0.0.1', '***': '128.0.0.1'}
print(url.with_query(query))
===================
https://mp.csdn.net:443/mp_blog/manage/article?xxx=127.0.0.1&***=128.0.0.1
url.update_query(query):对之前存在信息进行更新;
from yarl import URL
url = URL.build(
scheme='https',
host='mp.csdn.net',
port=443,
path='/mp_blog/manage/article',
query = {'spm': '1011.2124.3001.5298'}
)
query = {'xxx': '127.0.0.1', '***': '128.0.0.1'}
print(url.update_query(query))
=============================
https://mp.csdn.net:443/mp_blog/manage/article?spm=1011.2124.3001.5298&xxx=127.0.0.1&***=128.0.0.1
6> url / &%组合
from yarl import URL
url = (
URL('https://mp.csdn.net')/
'mp_blog/manage/article'%
{'spm': '1011.2124.3001.5298'}
)
print(url)
=====================
https://mp.csdn.net/mp_blog/manage/article?spm=1011.2124.3001.5298
二:yaml
1> yaml 介绍
Yaml :Yaml 是一种人类可读的数据序列化语言,通常用于存储项目中的配置文件;例如 docker 和 k8s 都使用 Yaml 文件定义部署信息;类似于 json 数据,但 Yaml 的格式更加丰富,可以存储更复杂的数据结构
2> yaml 基本规则
规则 | 说明 |
---|---|
层级关系 | yaml 的层级关系通过缩进表示,缩进空格数没有规定,但同层级的缩进必须一致。建议全局使用相同的缩进空格数; |
存储数据 | yaml 使用键值对的方式存储数据。 - 在键值对的值前面添加 - 符号表示这个键的值是一个列表 |
1. 数据结构介绍
YAML中,有3种基本的数据结构:Scalars(标量)、Sequences(序列)和Mappings(映射)
数据结构 | 说明 | 举例 |
---|---|---|
Scalars | 标量是单个的、不可再分的值。标量可以是字符串、数字、布尔值、null、日期等 | 1. 普通样式、单/双引号样式 2. 字面样式(literal ) 3. 折叠样式(folded) |
序列(Sequences) | 序列是一组按次序排列的值,每一个元素都可以是任意数据类型 | 连字符-开头的行构成一个序列; - A - B - C ==> key: [A, B, C] |
Mappings(映射) | 映射是一种键值对的集合,其中每个键都必须唯一 | 每个键值对用冒号+一个空格分隔(key: value) |
普通样式、单/双引号样式
import yaml
document = """
爱好1: 喝酒
唱歌
爱好2: '喝酒
唱歌'
"""
res = yaml.load(document, Loader=yaml.Loader)
print(res)
============
{'爱好1': '喝酒 唱歌', '爱好2': '喝酒\n唱歌'}
字面样式(literal )
import yaml
document = """
爱好1: |
喝酒
唱歌
爱好2: '喝酒
唱歌'
"""
res = yaml.load(document, Loader=yaml.Loader)
print(res)
=====================
{'爱好1': '喝酒\n唱歌\n', '爱好2': '喝酒\n唱歌'}
折叠样式(folded)
import yaml
document = """
爱好1: >
喝酒
唱歌
爱好2: '喝酒
唱歌'
"""
res = yaml.load(document, Loader=yaml.Loader)
print(res)
==============
{'爱好1': '喝酒 唱歌\n', '爱好2': '喝酒\n唱歌'}
Mappings(映射)
import yaml
document = """
爱好1: 喝酒
爱好2: 唱歌
"""
res = yaml.load(document, Loader=yaml.Loader)
print(res)
============
{'爱好1': '喝酒', '爱好2': '唱歌'}
2. 语法锚点和引用
编程中我们通常用变量引用来解决这种问题,YAML也提供了一种类似的机制实现变量引用,它就是锚点引用(Anchors and Aliases);例如:同的数据被重复使用, 配置信息,
定义锚点&引用锚点
import yaml
document = """
key: &anchor pig
key2: *anchor
key3: *anchor
"""
'''
1. 使用 & 符号可以定义一个锚点
2. * 符号+锚点名 可以引用先前定义的锚点
'''
res = yaml.load(document, Loader=yaml.Loader)
print(res)
=================
{'key': 'pig', 'key2': 'pig', 'key3': 'pig'}
锚定映射&序列节点
import yaml
document = """
# 定义一个共享的内容
common_data: &anchor_id
name: Common Name
value: Common Value
# 使用锚定引用共享内容
nodes:
- *anchor_id
- *anchor_id
"""
'''
1. common_data: &anchor_id: 是一个锚定的名字,它指向一个映射(即键值对的集合)
2. *anchor_id 是一个别名,用来引用先前定义的那个映射
3. nodes 是一个list, 引用anchor_id
'''
res = yaml.load(document, Loader=yaml.Loader)
print(res)
=================
{'common_data': {'name': 'Common Name', 'value': 'Common Value'}, 'nodes': [{'name': 'Common Name', 'value': 'Common Value'}, {'name': 'Common Name', 'value': 'Common Value'}]}
合并映射-merge key
YAML提供了一种<<语法用于合并映射(Mappings)。它允许你将一个映射的键值对合并到另一个映射中,从而实现映射之间的继承和合并。这种语法也被称为"merge key";
提高代码的可维护性和可读性。这对于定义共享的配置或基本设置,并在派生配置中进行定制化非常有用
import yaml
document = """
base: &tmp_base
name: John
age: 30
extension:
<<: *tmp_base
age: 31
city: New York
"""
# 在base基础上update extension 信息
res = yaml.load(document, Loader=yaml.Loader)
print(res)
===================
{'base': {'name': 'John', 'age': 30}, 'extension': {'name': 'John', 'age': 31, 'city': 'New York'}}
3. yaml tag
AML中,标签(Tags)用于对数据进行类型标识或自定义标识。它们提供了一种扩展YAML数据模型的方式;
tag 介绍
tag | 说明 | demo |
---|---|---|
!!str | 标识字符串类型 | name: !!str John |
!!int | 标识整数类型 | count: !!int 10 |
!!float | 标识浮点数类型 | pi: !!float 3.1415926 |
!!bool | 标识布尔类型 | is_valid: !!bool true |
!!null | 标识null | data: !!null |
隐式tag | 隐式声明 | boolean: !!bool "true" integer: !!int "3" |
显式tag | 显式声明 | boolean: true integer: 3 |
自定义tag
yaml tag | python type |
---|---|
!!null | None |
!!bool | bool |
!!int | int or long (int in Python 3) |
!!float | float |
!!binary | str (bytes in Python 3) |
!!timestamp | datetime.datetime |
!!omap, !!pairs | list of pairs |
!!set | set |
!!str | str or unicode (str in Python 3) |
!!seq | list |
!!map | dict |
Python-specific | tags |
!!python/none | None |
!!python/bool | bool |
!!python/bytes | (bytes in Python 3) |
!!python/str | str (str in Python 3) |
!!python/unicode | unicode (str in Python 3) |
!!python/int | int |
!!python/long | long (int in Python 3) |
!!python/float | float |
!!python/complex | complex |
!!python/list | list |
!!python/tuple | tuple |
!!python/dict | dict |
3> yaml demo
配置文件用 .yaml 或者 .py 形式如下
1. yaml.load
import yaml
document = """
conv_001:
op_list:
- Conv2d
- Conv2d
creat_params:
selector:
- F
- F
layer1:
in_channels: 1
out_channels: 1
kernel_size: 3
stride: 2
padding: 1
groups: 1
layer2:
in_channels: 1
out_channels: 2
kernel_size: 3
stride: 4
padding: 1
groups: 1
quant_params:
data_num: 1
inputShape:
- [1, 1, 224, 8]
"""
res = yaml.load(document, Loader=yaml.Loader)
print(res)
print(type(res))
=======================
{'conv_001': {'op_list': ['Conv2d', 'Conv2d'], 'creat_params': {'selector': ['F', 'F'], 'layer1': {'in_channels': 1, 'out_channels': 1, 'kernel_size': 3, 'stride': 2, 'padding': 1, 'groups': 1}, 'layer2': {'in_channels': 1, 'out_channels': 2, 'kernel_size': 3, 'stride': 4, 'padding': 1, 'groups': 1}}, 'quant_params': {'data_num': 1, 'inputShape': [[1, 1, 224, 8]]}}}
<class 'dict'>
2. yaml.load Unicode&yaml.Loader
使用 Loader=yaml.Loader 实现Unicode
import yaml
document = """
姓名: 小明,
爱好:
- 喝酒
- 唱歌
- 赌牌
- 打游戏
"""
res = yaml.load(document, Loader=yaml.Loader)
print(res)
print(type(res))
3. yaml.dump&Unicode
import yaml
import os
document = """
姓名: 小明,
爱好:
- 喝酒
- 唱歌
- 赌牌
- 打游戏
"""
res = yaml.load(document, Loader=yaml.Loader)
document_name = f'document.yaml'
with open(document_name, 'w') as file:
yaml.dump(res, file, default_flow_style=False, encoding='utf-8', allow_unicode=True)
'''
数据中包含中文等 Unicode 字符,yaml.dump() 会将它们编码成不可读的表示方式。为了解决这个问题,
可以添加三个关键字参数,使中文等 Unicode 字符以可读形式保存,default_flow_style, encoding, allow_unicode
'''
print(os.path.exists(document_name))
with open(document_name, 'r') as f:
res_load = yaml.load(f, Loader=yaml.Loader)
print(res_load)
===================
True
{'姓名': '小明,', '爱好': ['喝酒', '唱歌', '赌牌', '打游戏']}
4. yaml.load_all
aml文档中,使用 --- 符号可以分段。对于带有分段的Yaml文档,使用 yaml.load() 函数会报错,需要使用 yaml.load_all() 函数;
import yaml
document = """
姓名: 小明,
爱好:
- 喝酒
- 唱歌
- 赌牌
- 打游戏
---
姓名: 小红,
爱好:
- 写字
- 看书
"""
res = yaml.load_all(document, Loader=yaml.Loader)
print(type(res))
for i in res:
print(i)
====================
<class 'generator'>
{'姓名': '小明,', '爱好': ['喝酒', '唱歌', '赌牌', '打游戏']}
{'姓名': '小红,', '爱好': ['写字', '看书']}
5. yaml 与编码对象class
import yaml
class Anmails:
def __init__(self, name, likes):
self.name = name
self.likes = likes
def __repr__(self):
return f'{self.__class__.__name__}(name={self.name}, like={self.likes})'
def like(self):
print(f'我是{self.name},我喜欢{str(self.likes)}! ')
to_do = Anmails('猪', ['喝酒', '唱歌', '赌牌', '打游戏'])
document = yaml.dump(to_do)
like_A = yaml.load(document, Loader=yaml.Loader)
print(yaml.dump(to_do))
print(like_A)
print(type(like_A))
like_A.like()
=======================
!!python/object:__main__.Anmails
likes:
- "\u559D\u9152"
- "\u5531\u6B4C"
- "\u8D4C\u724C"
- "\u6253\u6E38\u620F"
name: "\u732A"
Anmails(name=猪, like=['喝酒', '唱歌', '赌牌', '打游戏'])
<class '__main__.Anmails'>
我是猪,我喜欢['喝酒', '唱歌', '赌牌', '打游戏']!
6. yaml 多个编码对象class
import yaml
class Anmails:
def __init__(self, name, likes):
self.name = name
self.likes = likes
def __repr__(self):
return f'{self.__class__.__name__}(name={self.name}, like={self.likes})'
def like(self):
print(f'我是{self.name},我喜欢{str(self.likes)}! ')
to_do1 = Anmails('猪', ['喝酒', '唱歌', '赌牌', '打游戏'])
to_do2 = Anmails('de-lovely', ['写字', '看书'])
document_name = r'document.yaml'
with open(document_name, 'w') as f:
yaml.dump_all([to_do1, to_do2], f, default_flow_style=False, encoding='utf-8', allow_unicode=True)
==============
document.yaml:
!!python/object:__main__.Anmails
likes:
- 喝酒
- 唱歌
- 赌牌
- 打游戏
name: 猪
--- !!python/object:__main__.Anmails
likes:
- 写字
- 看书
name: de-lovely
7. yaml.safe_load
import yaml
document_name = 'document.yaml'
with open(document_name, 'r') as f:
# case_params = yaml.load(f, Loader=yaml.Loader)
case_params = yaml.safe_load(f)
print(case_params)
#修改参数
case_params['conv_001']['creat_params']['layer1']['groups'] = 2
case_params['conv_001']['op_list'][0] = 'Conv3d'
#保存参数
with open('document_currect.yaml', 'w') as file:
yaml.dump(case_params, file)
4> yaml 三大组件
1. 构造器、表示器、解析器 介绍
组件 | 功能 | 描述 |
---|---|---|
Constructors(构造器) | 用于将 YAML 数据解析为 Python 对象的组件,将 YAML 数据的不同类型转换为相应的 Python 对象。 | PyYAML 提供了一些内置的构造器,用于处理常见的数据类型,如字符串、整数、浮点数、布尔值等。同时,你也可以自定义构造器,以便将 YAML 数据解析为自定义的 Python 类型。通过注册构造器,你可以扩展 PyYAML 的解析功能,使其能够处理更多的数据类型; |
Representers(表示器) | 与构造器相反,Representers 是用于将 Python 对象表示为 YAML 数据的组件,它们负责将 Python 对象转换为 YAML 中的相应表示形式 | PyYAML 提供了一些内置的表示器,用于处理常见的 Python 对象类型,如字符串、整数、浮点数、布尔值等。同时,你也可以自定义表示器,以便将自定义的 Python 类型表示为 YAML 数据。通过注册表示器,你可以定制 PyYAML 的转储功能,使其能够生成符合特定需求的 YAML 数据。 |
Resolvers(解析器) | Resolvers 是用于解析 YAML 数据中的标签(Tags)的组件,它们负责识别标签并将其映射到相应的构造器和表示器 | PyYAML 提供了内置的标签解析器,用于处理常见的标准类型。同时,你也可以自定义解析器,以便识别和处理自定义的标签。通过注册解析器,你可以扩展 PyYAML 的标签识别功能,使其能够处理更多的数据类型和标签; |
2. 构造&转存
import yaml
class Introduce(yaml.YAMLObject):
yaml_tag = u'!Introduce'
def __init__(self, name, likes):
self.name = name
self.likes = likes
def __repr__(self):
return f'{self.__class__.__name__}(name={self.name}, {self.likes})'
document = """
!Introduce
name: xiaoming
likes:
- games
"""
'''
1. !Introduce: 定义一个YAML标签用于解析和生成Monster类型数据
2. yaml.dump(res): 转储Monster对象为YAML格式数据
'''
res = yaml.load(document, Loader=yaml.Loader)
print(res)
print(type(res))
document_cp = yaml.dump(res)
print(document_cp)
=================
Introduce(name=xiaoming, ['games'])
<class '__main__.Introduce'>
!Introduce
likes:
- games
name: xiaoming
3. 序列化构造器
import yaml
class Dice(tuple):
def __new__(cls, a, b):
return tuple.__new__(cls, [a, b])
def __repr__(self):
return "Dice(%s,%s)" % self
def dice_representer(dumper, data):
return dumper.represent_scalar(u'!dice', u'%sd%s' % data)
yaml.add_representer(Dice, dice_representer)
res = yaml.dump(Dice(3,6))
print(res)
============
!dice '3d6'
无:# yaml.add_representer(Dice, dice_representer)
=========================
!!python/object/new:__main__.Dice
- !!python/tuple
- 3
- 6
4. 自定义构造器
import yaml
class Dice(tuple):
def __new__(cls, a, b):
return tuple.__new__(cls, [a, b])
def __repr__(self):
return "Dice(%s,%s)" % self
def dice_representer(dumper, data):
return dumper.represent_scalar(u'!dice', u'%sd%s' % data)
def dice_constructor(loader, node):
value = loader.construct_scalar(node)
a, b = map(int, value.split('d'))
return Dice(a, b)
yaml.add_constructor(u'!dice', dice_constructor)
res = yaml.load("initial hit points: !dice 8d4", yaml.Loader)
print(res)
==========
{'initial hit points': Dice(8,4)}
5> yaml引用环境变量
import yaml
import os
def render_env_constructor(loader, node):
value = loader.construct_scalar(node)
return os.path.expandvars(value)
yaml.SafeLoader.add_constructor('!ENV', render_env_constructor)
os.environ["a"]="111"
os.environ["b"]="222"
res = yaml.safe_load("test: !ENV a=${a}, b=$b")
#加载YAML时自动替换了标签!ENV标识标量的环境变量占位符
print(res)
=======
{'test': 'a=111, b=222'}
环境变量通常都是字符串形式。如果你使用了数字、布尔等其他类型,需要解析后手动转换。
os.path.expandvars是一个内置函数,用于展开字符串中的环境变量。它会在目标字符串中查找形式为 V A R 或 VAR或 VAR或{VAR}的环境变量引用,并将其替换为响应的环境变量的值。如果找不到匹配的环境变量,那么引用保持不变
6> libyaml
libyaml | 介绍 |
---|---|
libyaml库 | libyaml是一个独立的C库,用于处理 yaml数据的解析和生成。Pyyaml 可以使用 LibYAML 作为其解析和生成 yaml 数据的底层引擎; |
特点 | LibYAML 具有高性能、低内存占用、加速 yaml数据处理 |
组件 | 提供 CLoader 和 CDumper 两个组件用来集成 LibYAML; CLoader: PyYAML 的解析器(Loader)的C扩展版本 CDumper: PyYAML的生成器(Dumper)的C扩展版本 |
CLoader和CDumper优势 | 1. 通过与LibYAML的集成,提供了更高效的解析和生成功能; 2. 处理大型YAML数据时获得更好的性能和效率 |
7> FAQ
1. yaml.safe_load&load区别
load: Loader支持加载任意的Python对象,可能导致执行任意 Python 代码
safe_load:SafeLoader 限制了加载过程中执行的操作,只允许加载基本类型的对象,如字符串、整数、列表和字典等;当你处理来自不受信任的源或不确定性的 YAML 文件时,特别是从外部来源加载时,使用 SafeLoader 是一个良好的实践,可以提高安全性并防止可能的代码注入或其他潜在的安全问题