1 configparser模块

用于生成修改常见配置文档,当前模块的名称在 python 3.x 版本中变更为 configparser。它提供类似于 Microsoft Windows INI文件的结构。 ConfigParser允许编写可由最终用户轻松定制的 Python 程序。

配置文件由各部分组成,后跟选项的键/值对段名用[]字符分隔。 这些键/值对:或=隔开。 注释以#或;开头。

1、如下,好多软件的常见配置文件:

首先说明几个概念:

  • 下面的[bitbucket.org][]包围起来的是section,可以理解为节点
  • 节点下面的是键值对,这个键就是option
    然后再接着往下看就会明白section和option这个概念了!

注意:

DEFAULT这个关键字不属于section!我也不太明白

[DEFAULT]   # 节点section DEFAULT
# 下面是该节点对应所有键(option)/值对信息
serveraliveinterval = 45
compression = yes
compressionlevel = 9
forwardx11 = yes


[bitbucket.org]  # 节点section bitbucket.org
# 下面是该节点对应所有键/值对信息
user = hg

[topsecret.server.com]  # 节点 section topsecret.server.com
# 下面是该节点对应所有键/值对信息
host port = 50022
forwardx11 = no

2、使用configparser模块生成上面的配置文件

import configparser

config = configparser.ConfigParser()

# DEFALULT 就相当于时一个字典的key
# 对应的value还是一个字典,相当于时一个嵌套字典
config["DEFAULT"] = {'ServerAliveInterval': '45',
                      'Compression': 'yes',
                     'CompressionLevel': '9'}

config['bitbucket.org'] = {}
config['bitbucket.org']['User'] = 'hg'
config['topsecret.server.com'] = {}
topsecret = config['topsecret.server.com']
topsecret['Host Port'] = '50022'     # mutates the parser
topsecret['ForwardX11'] = 'no'  # same here
config['DEFAULT']['ForwardX11'] = 'yes'
with open('config.ini', 'w') as configfile:
   config.write(configfile)

生成config.ini结果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qqCtrHR1-1646310028648)(./imgs/cp1.png)]

3、读取配置文件

import configparser

def read_config():
    # 1 读取解析 .ini配置文件
    config = configparser.ConfigParser()
    # .ini配置文件中添加的有中文注释,因此需要utf-8编码读取,否则会报错
    config.read('config.ini', encoding='utf-8')

    # 2 sections() 读取所有部分,以列表的形式返回所有节点信息
    sections = config.sections()
    # 节点 [DEFAULT] 并没有读取到列表,不清楚为什么
    print(sections)   # ['bitbucket.org', 'topsecret.server.com']

    # 3 获取指定节点的所有配置信息,以列表的形式返回某个节点及其之前的所有配置信息,如果该节点与前面的节点有相同的key则覆盖
    items1 = config.items('DEFAULT')
    items2 = config.items('bitbucket.org')
    items3 = config.items('topsecret.server.com')
    print(items1) 
    # [('serveraliveinterval', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('forwardx11', 'yes')]
    print(items2)
    # [('serveraliveinterval', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('forwardx11', 'yes'), ('user', 'hg')]
    print(items3)
    # [('serveraliveinterval', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('forwardx11', 'no'), ('host port', '50022')]
    # 注意观察,[topsecret.server.com] 节点下 ('forwardx11', 'no') 会覆盖之前的配置,如果有相同的key,后面的key值会覆盖前面的key值,和添加字典一样!

    # 4 获取指定节点下指定的options值,返回节点下所有key值的列表
    # keys1 = config.options('DEFAULT')     # DEFAULT 并不属于sections,感觉这个应该是一个比较特殊的关键字,不解析
    # configparser.NoSectionError: No section: 'DEFAULT'
    keys2 = config.options('bitbucket.org')
    keys3 = config.options('topsecret.server.com')
    # 然后把DEFALUT的key追加到每个节点的后面
    print(keys2)  # ['user', 'serveraliveinterval', 'compression', 'compressionlevel', 'forwardx11']
    print(keys3)  # ['host port', 'forwardx11', 'serveraliveinterval', 'compression', 'compressionlevel']

    # 5、获取指定节点下指定的option值,就是获取指定节点下key对应的值
    '''
    ConfigParserObject.get(section, option)
    返回结果是字符串类型
    ConfigParserObject.getint(section, option)
    返回结果是int类型
    ConfigParserObject.getboolean(section, option)
    返回结果是bool类型
    ConfigParserObject.getfloat(section, option)
    返回结果是float类型
    '''
    user = config.get('bitbucket.org', 'user')
    print(user, type(user))  # hg <class 'str'>
    interval = config.get('DEFAULT', 'serveraliveinterval')
    print(interval, type(interval))  # 45 <class 'str'>
    interval2 = config.getint('DEFAULT', 'serveraliveinterval')
    print(interval2, type(interval2))  # 45 <class 'int'>

    # 5 检查section(节点) 或 option(键值)是否存在
    # 如果存在返回True,否则返回False
    # 检查section是否存在
    res1 = config.has_section('DEFAULT')
    res2 = config.has_section('bitbucket.org')
    print(res1, res2)   # False True
    # 检查option是否存在
    res3 = config.has_option('DEFAULT', 'forwardx11')
    res4 = config.has_option('bitbucket.org', 'user')
    print(res3, res4)  # True True
    # 可以看出DEFAULT 不属于section节点,但是DEFAULT又可以作为section获取下面的key,疑惑!

if __name__ == '__main__':
    # write_config()
    read_config()
>>> import configparser
>>> config = configparser.ConfigParser()
>>> config.sections()
[]
>>> config.read('example.ini')
['example.ini']
>>> config.sections()
['bitbucket.org', 'topsecret.server.com']
>>> 'bitbucket.org' in config
True
>>> 'bytebong.com' in config
False
>>> config['bitbucket.org']['User']
'hg'
>>> config['DEFAULT']['Compression']
'yes'
>>> topsecret = config['topsecret.server.com']
>>> topsecret['ForwardX11']
'no'
>>> topsecret['Port']
'50022'
>>> for key in config['bitbucket.org']: print(key)
...
user
compressionlevel
serveraliveinterval
compression
forwardx11
>>> config['bitbucket.org']['ForwardX11']
'yes'

3、configparser的增删改查语法

import ConfigParser

config = ConfigParser.ConfigParser()
config.read('i.cfg')

# ########## 读 ##########
#secs = config.sections()
#print secs
#options = config.options('group2')
#print options

#item_list = config.items('group2')
#print item_list

#val = config.get('group1','key')
#val = config.getint('group1','key')

# ########## 改写 ##########
#sec = config.remove_section('group1')
#config.write(open('i.cfg', "w"))

#sec = config.has_section('wupeiqi')
#sec = config.add_section('wupeiqi')
#config.write(open('i.cfg', "w"))


#config.set('group2','k1',11111)
#config.write(open('i.cfg', "w"))

#config.remove_option('group2','age')
#config.write(open('i.cfg', "w"))

参考https://www.jianshu.com/p/417738fc9960
参考https://geek-docs.com/python/python-tutorial/python-configparser.html
参考https://docs.python.org/3/library/configparser.html

2 PyYAML模块

1、PyYAML模块安装

pip install PyYAML

2、yaml文件的语法格式参考

3、yaml使用

2.2 yaml基本使用
yolov5中就是通过yaml文件来配置模型的定义:

参考:https://github.com/ultralytics/yolov5/blob/c72270c076e1f087d3eb0b1ef3fb7ab55fe794ba/models/yolo.py

2.2.1 使用yaml.load()读取yaml文件,并获取其中的配置信息

1、首先有一个配置文件config.yaml,内容如下:

optimizer:
 - SGD
 - Adam 
train:
  optimization: Adam
  learning_rate: 0.001
  batch_size: 64
  epoch: 200

2、读取yaml文件

  • data_dict = yaml.load(f, Loader=yaml.FullLoader):把yaml文件解析成字典
  • 使用字典的key获取对应的值

import yaml


def read_yaml():
    yaml_f = open('./config.yaml', 'r', encoding='utf-8')
    data_dict = yaml.load(yaml_f, Loader=yaml.FullLoader)
    print(type(data_dict))
    print(data_dict)  
    # {'optimizer': ['SGD', 'Adam'], 'train': {'optimization': 'Adam', 'learning_rate': 0.001, 'batch_size': 64, 'epoch': 200}}

    # 因为yaml文件被解析成字典的形式了,因此就可以通过字典的形式进行访问对应的值了
    lr = data_dict['train']['learning_rate']
    print(lr, type(lr))  # 0.001 <class 'float'>
if __name__ == '__main__':
    read_yaml()

2.2.2 使用yaml.load_all()读取多个yaml文档

1、使用配置文件docs.yaml如下:

我们在docs.yaml中有两个文档。 文件用---分隔。(--- 加不加都是一样的,只是方便区分而已)

cities:
  - Bratislava
  - Kosice
  - Trnava
  - Moldava
  - Trencin
---
companies:
  - Eset
  - Slovnaft
  - Duslo Sala
  - Matador Puchov

2、读取多个yaml文档

  • docs_generator = yaml.load_all(yaml_f, Loader=yaml.FullLoader):读取得到的是一个迭代器
  • 迭代器中存储的是一个一个的字典数据,可以循环遍历获取
import yaml

def read_docs_yaml():
    yaml_f = open('./docs.yaml', 'r', encoding='utf-8')
    # 读取的是一个迭代器
    docs_generator = yaml.load_all(yaml_f, Loader=yaml.FullLoader)
    print(type(docs_generator))  # <class 'generator'>
    print(docs_generator)  # <generator object load_all at 0x000001C0F2D51200>

    # 迭代器中存储的就是两个字典
    # docs_list = list(docs_generator)
    # print(docs_list)
    # [{'cities': ['Bratislava', 'Kosice', 'Trnava', 'Moldava', 'Trencin']}, {'companies': ['Eset', 'Slovnaft', 'Duslo Sala', 'Matador Puchov']}]

    for doc in docs_generator:
        for key, value in doc.items():
            print(key, '->', value)
            # cities -> ['Bratislava', 'Kosice', 'Trnava', 'Moldava', 'Trencin']
            # companies -> ['Eset', 'Slovnaft', 'Duslo Sala', 'Matador Puchov']



if __name__ == '__main__':
    read_docs_yaml()

2.2.3 把数据序列化成yaml格式,并写入到yaml文件

1、如下,把数据写入到yaml文件中

import yaml

def write_yaml():
    users = [{'name': 'John Doe', 'occupation': 'gardener'},
            {'name': 'Lucy Black', 'occupation': 'teacher'}]

    data_str = yaml.dump(users)
    print(type(data_str))  # <class 'str'>
    print(data_str)
    '''
    - name: John Doe
      occupation: gardener
    - name: Lucy Black
      occupation: teacher
    '''

    with open('users.yaml', 'w') as f:
        # dump() 第一个参数是数据,第二个参数是文件对象
        data = yaml.dump(users, f)

if __name__ == '__main__':
    write_yaml()

生成users.yaml文件内容如下:

- name: John Doe
  occupation: gardener
- name: Lucy Black
  occupation: teacher

2、示例2

import yaml

def write_yaml2():

    train_config = {'optimizer':['SGD', 'Adam'],
                    'train':{'optimization': 'Adam',
                             'learning_rate': 0.001,
                             'batch_size': 64,
                             'epoch': 200}}

    with open('train_config.yaml', 'w') as f:
        data = yaml.dump(train_config, f)

if __name__ == '__main__':
    write_yaml2()

生成train_config.yaml文件内容如下:

optimizer:
- SGD
- Adam
train:
  batch_size: 64
  epoch: 200
  learning_rate: 0.001
  optimization: Adam

2.2.4 读取yaml文件,并对键值进行排序

1、items.yaml文件内容为:

raincoat: 1
coins: 5
books: 23
spectacles: 2
chairs: 12
pens: 6

2、对读取的yaml内容按照key进行排序

import yaml

def read_yaml_sorted_key():
    with open('items.yaml', 'r') as f:
        data_dict = yaml.load(f, Loader=yaml.FullLoader)
        print(type(data_dict))  # <class 'dict'>
        print(data_dict)
        # {'raincoat': 1, 'coins': 5, 'books': 23, 'spectacles': 2, 'chairs': 12, 'pens': 6}

        sorted = yaml.dump(data_dict, sort_keys=True)
        print(type(sorted))  # <class 'str'>
        print(sorted)
        '''
        books: 23
        chairs: 12
        coins: 5
        pens: 6
        raincoat: 1
        spectacles: 2
        '''

        # 你也可以把排序后的配置写到一个新的文件中
        with open('items_new.yaml', 'w') as f2:
            yaml.dump(data_dict, f2, sort_keys=True)

if __name__ == '__main__':
    read_yaml_sorted_key()