最全總結 | 聊聊 Python 資料處理全家桶(配置篇)

AirPython發表於2020-10-07

image

1.前言

在實際專案中,經常會接觸到各種各樣的配置檔案,它可以增強專案的可維護性

常用配件檔案的處理方式,包含:JSON、ini / config、YAML、XML 等

本篇文章,我們將聊聊 Python 資料處理全家桶之配置檔案大總結

​2.JSON

Python 內建了 JSON 模組,可以非常方便操作 JSON 資料

常見的 4 個方法分別是:

  • json.load(json_file)

    解析 JSON 檔案,轉換為 Python 中對應的資料型別

  • json.loads(json_string)

    解析 JSON 格式的字串,結果為 Python 中的字典

  • json.dump(python_content,file_path)

    將 Python 資料,包含:dict、list 寫入到檔案中

  • json.dumps(python_dict)

    將 Python 中 dict 轉為 JSON 格式的字串

以下面這段 JSON 配置檔案為例:

#config.json
{
  "mysql": {
    "host": "198.0.0.1",
    "port": 3306,
    "db": "xh",
    "username": "root",
    "password": "123456",
    "desc": "Mysql配置檔案"
  }
}

1、讀取配置檔案

讀取配置檔案有兩種方式,分別是:

使用 json.load() 直接讀取配置檔案

或者,先讀取配置檔案中的內容,然後使用 json.loads() 轉換為 Python 資料型別

需要指出的是,面對複雜層級的 JSON 配置檔案,可以利用 jsonpath 進行讀取;jsonpath 類似於 xpath,可以通過正規表示式快速讀取資料

import json

def read_json_file(file_path):
    """
    讀取json檔案
    :param file_path:
    :return:
    """
    with open(file_path, 'r', encoding='utf-8') as file:

        # 讀取方式二選一
        # 方式一
        result = json.load(file)

        # 方式二
        # result = json.loads(file.read())

        # 解析資料
        host_mysql = result['mysql']['host']
        port_mysql = result['mysql']['port']
        db = result['mysql']['db']

        print('Mysql地址:', host_mysql, ",埠號:", port_mysql, ",資料庫:", db)
​
    return result

2、儲存配置檔案

使用 json 中的 json.dump() 方法,可以將一個字典寫入到 JSON 檔案中

def write_content_to_json_file(output_file, content):
    """
    寫入到json檔案中
    :param output_file:
    :param content:
    :return:
    """
    with open(output_file, 'w') as file:
        # 寫入到檔案中
        # 注意:為了保證中文能正常顯示,需要設定ensure_ascii=False
        json.dump(content, file, ensure_ascii=False)

content_dict = {
    'mysql': {
        'host': '127.0.0.1',
        'port': 3306,
        'db': 'xh',
        'username': 'admin',
        'password': '123456',
        'desc': 'Mysql資料庫'
    }
}

write_content_to_json_file('./output.json', content_dict)

3、修改配置檔案

如果需要修改配置檔案,只需要先從配置檔案中讀出內容,然後修改內容,最後將修改後的內容儲存的配置檔案中即可

def modify_json_file():
    """
    修改json配置檔案
    :return:
    """
    result = read_json_file('./config.json')

    # 修改
    result['mysql']['host'] = '198.0.0.1'

    write_content_to_json_file('./config.json', result)

3.ini/config

ini 配置檔案和 config 配置檔案的解析方式類似,僅僅是檔案字尾不一致

這裡我們以 ini 配置檔案為例

# config.ini
[mysql]
host = 139.199.1.1
username = root
password = 123456
port = 3306

ini 檔案由 3 部分組成,分別是:節點(Section)、鍵(Key)、值(Value)

常見的 Python 處理 ini 檔案有兩種方式,包含:

  • 使用內建的 configparser 標準模組

  • 使用 configobj第三方依賴庫

我們先來看看內建的 configparser 模組

3.1.1 讀取配置檔案

例項化一個 ConfigParser 解析物件,使用 read() 方法讀取 ini 配置檔案

from configparser import ConfigParser

# 例項化解析物件
cfg = ConfigParser()

# 讀取ini檔案內容
cfg.read(file_path)

使用 sections()函式,可以獲取所有的節點列表

# sections() 得到所有的section,並以列表的形式返回
sections = cfg.sections()
print(sections)

要獲取某一個節點下的所有鍵,可以使用 options(section_name) 函式

# 獲取某一個區域的所有key
# cfg.options(section_name)
keys = cfg.options('mysql')
print(keys)

通過 items(section_name) 函式,可以獲取某一個節點下的所有鍵值對

# 獲取某一個區域下的鍵值對
items = cfg.items("mysql")
print(items)

如果要獲取某一個節點下,某一個鍵下的值,使用 get(section_name,key_name) 函式即可

# 讀取某一個區域下的某一個鍵值
host = cfg.get("mysql", "host")
print(host)

3.1.2 寫入配置檔案

和讀取配置檔案類似,需要先例項化一個 ConfigParser 解析物件

首先,使用 add_section(section_name) 函式新增一個節點

# 加入節點和鍵值對
# 新增一個節點
cfg.add_section("redis")

然後,就可以使用 set(section_name,key,value) 函式往某一個節點新增鍵值對

# 往節點內,新增鍵值對
cfg.set("redis", "host", "127.0.0.1")
cfg.set("redis", "port", "12345")

最後,使用 write() 函式寫入到配置檔案中去

# 寫入到檔案中
cfg.write(open('./raw/output.ini', 'w'))

3.1.3 修改配置檔案

修改配置檔案的步驟是,讀取配置檔案,然後通過 set(section_name,key,value) 進行修改操作,最後使用 write() 函式寫入到檔案中即可

def modify_ini_file(file_path):
    """
    修改ini檔案
    :return:
    """
    cfg.read(file_path)

    cfg.set("mysql", "host", "139.199.11.11")

    # 寫入
    cfg.write(open(file_path, "w"))

接著,我們聊聊使用 configobj 操作 ini 配置檔案的流程

首先安裝 configobj 依賴庫

# 依賴
# pip3 install configobj

3.2.1 讀取配置檔案

直接將 ini 配置檔案路徑作為引數,使用 ConfigObj 類構造一個物件

from configobj import ConfigObj

# 例項化物件
config = ConfigObj(file_path, encoding='UTF8')

檢視原始碼可以發現,ConfigObj 是 Section 節點的子類,而 Section 是 Dict 字典的子類

image

所以,可以直接通過鍵名 Key 獲取節點和鍵值

# <class 'configobj.ConfigObj'>
print(type(config))

# <class 'configobj.Section'>
print(type(config['mysql']))

# 節點
print(config['mysql'])

# 某一個鍵對應的值
print(config['mysql']

3.2.2 修改配置檔案

只需要讀取配置檔案,然後直接修改 ConfigObj 物件,最後使用 write() 方法,即可以達到修改配置檔案的目的

def modify_ini_file(file_path):
    """
    修改ini檔案
    :param file_path:
    :return:
    """
    # 讀取配置檔案
    config = read_ini_file(file_path)

    # 直接修改
    config['mysql']['host'] = '139.199.1.1'

    # 刪除某個鍵值對
    try:
        del config['mysql']['db']
    except Exception as e:
        print('鍵不存在')
        pass

    # 寫入
    config.write()

3.2.3 寫入配置檔案

寫入配置檔案,首先需要例項化一個 ConfigObj 物件,傳入檔案路徑

然後,設定節點、針對節點設定鍵值對

最後,呼叫 write() 方法,寫入到配置檔案中

def write_to_ini_file(output):
    """
    寫入到ini檔案中
    :param output:
    :return:
    """
    config = ConfigObj(output, encoding='UTF8')
    config['website'] = {}
    config['website']['url'] = "www.baidu.com"
    config['website']['name'] = "百度"

    # 儲存
    config.write()

4.YAML

Python 操作 YAML 檔案,常見的 2 種方式分別是:pyyaml、ruamel.yaml

使用 pip 安裝依賴

# 安裝依賴
# 方式一
pip3 install pyyaml

# 方式二
pip3 install ruamel.yaml

下面以一個簡單的 YAML 配置檔案為例,通過兩種方式進行說明

# 水果
Fruits:
  # 蘋果
  - Apple:
      name: apple
      price:  1
      address:  廣東
  # 桔子
  - Orange:
      name: orange
      price:  3
      address:  湖南
  # 香蕉
  - Banana:
      name: banana
      price:  2
      address:  海南

我們先來看看 pyyaml

4.1.1 讀取配置檔案

首先,讀取配置檔案,使用 yaml.safe_load() 載入資料,獲取的資料型別是字典

import yaml

with open(file_path, "r") as file:
    data = file.read()

    # safe_load() 讀取配置檔案
    # 結果資料型別:dict
    result = yaml.safe_load(data)

    print(result)

接著,就可以通過 YAML 配置檔案的層級關係,獲取鍵值

# 3、獲取yaml中的值
name = result['Fruits'][0]['Apple']['name']
price = result['Fruits'][0]['Apple']['price']
address = result['Fruits'][0]['Apple']['address']
print("名稱:", name, ",price:", price, ",address:", address)

4.1.2 寫入配置檔案

使用 YAML 中的 dump() 方法,可以將一個字典寫入到 YAML 配置檔案中

需要注意的是,為了保證中文寫入能正常顯示,需要配置 allow_unicode=True

def write_to_yaml_file(content, file_path):
    """
    寫入到yaml檔案中
    :param content:
    :param file_path:
    :return:
    """

    # 寫入到檔案中
    with open(file_path, 'w', encoding='utf-8') as file:
        yaml.dump(content, file, default_flow_style=False, encoding='utf-8', allow_unicode=True)

# 定義一個字典
content = {
   "websites": [{"baidu": {'url': "www.baidu.com", 'name': '百度', "price": 100}},{"alibaba": {'url': "www.taobao.com", 'name': '淘寶', "price": 200}},{"tencent": {'url': "www.tencent.com", 'name': '騰訊', "price": 300}},]
}

write_to_yaml_file(content, "./raw/new.yaml")

4.1.3 修改配置檔案

和修改 ini 檔案型別,先讀取配置檔案,然後修改字典中的內容,最後使用上面的寫入方法,即可以達到修改配置檔案的目的

def modify_yaml_file():
    """
    修改yaml檔案
    :return:
    """
    content = read_yaml_file('./raw/norm.yaml')
    print(content)

    # 修改dict
    content['Fruits'][0]['Apple']['price'] = 10086

    # 重新寫入到一個新的yaml檔案中
    write_to_yaml_file(content, './raw/output.yaml')

接著,我們來聊聊使用 ruamel 操作 YAML 配置檔案的流程

ruamel 是 pyyaml 的衍生版本,在傳統 pyyaml 的基礎上,增加了 RoundTrip 模式,保證 YAML 配置檔案的讀寫順序一致

所以,在讀取、修改、寫入方式上和 pyyaml 類似

4.2.1 讀取配置檔案

from ruamel import yaml

def read_yaml_file(file_path):
    """
    讀取yaml檔案
    :param file_path:
    :return:
    """
    with open(file_path, 'r', encoding='utf-8') as file:
        data = file.read()

        # 解析yaml檔案
        # 型別:ordereddict
        result = yaml.load(data, Loader=yaml.RoundTripLoader)

        name = result['Fruits'][0]['Apple']['name']
        price = result['Fruits'][0]['Apple']['price']
        address = result['Fruits'][0]['Apple']['address']
        print("名稱:", name, ",price:", price, ",address:", address)

    return result

4.2.2 寫入配置檔案

def write_to_yaml_file(filepath, data):
    """
    寫入到yaml檔案中
    :param filepath:
    :param data:
    :return:
    """
    with open(filepath, 'w', encoding='utf-8') as file:
        yaml.dump(data, file, Dumper=yaml.RoundTripDumper, allow_unicode=True)

4.2.3 修改配置檔案

def modify_yaml_file():
    """
    修改yaml檔案
    :return:
    """
    content = read_yaml_file('./raw/norm.yaml')

    print(content)

    # 修改dict
    content['Fruits'][0]['Apple']['price'] = 10086

    # 重新寫入到一個新的yaml檔案中
    write_to_yaml_file('./raw/output.yaml', content)

5.XML

XML 作為一種標記語言,被用來設計儲存和傳輸資料,很多專案經常使用 XML 作為配置檔案和資料傳輸型別

Python 內建的 xml 模組 可以很方便地處理 XML 配置檔案

以下面這段配置檔案為例:

<?xml version="1.0" encoding="utf-8"?>
<dbconfig>
    <mysql>
        <host>127.0.0.1</host>
        <port>3306</port>
        <dbname>test</dbname>
        <username>root</username>
        <password>4355</password>
    </mysql>
</dbconfig>

首先,使用 xml.dom.minidom.parser(file_path) 解析配置檔案,利用 documentElement 屬性獲取 XML 根節點

import xml.dom.minidom

# 讀取配置檔案
dom = xml.dom.minidom.parse("./raw.xml")

# 利用 documentElement 屬性獲取 XML 根節點
# 根節點
root = dom.documentElement

接著,使用 getElementsByTagName(tag_name) 方法,獲取某一節點

# 獲取mysql節點
node_mysql = root.getElementsByTagName('mysql')[0]

最後,使用 childNodes 屬性,遍歷節點的子 Node 節點,獲取節點的名稱和值

# 遍歷子節點,獲取名稱和值
for node in node_mysql.childNodes:
    # 節點型別
    # 1:Element
    # 2:Attribute
    # 3:Text
    # print(node.nodeType)
    if node.nodeType == 1:
        print(node.nodeName, node.firstChild.data)

6.最後

到此,Python 資料全家桶以全部完結!

我已經將文中全部原始碼上傳到後臺,關注公眾號「 AirPython 」後回覆「 dball 」即可獲得全部原始碼

如果你覺得文章還不錯,請大家 點贊、分享、留言下,因為這將是我持續輸出更多優質文章的最強動力!

推薦閱讀
聊聊 Python 資料處理全家桶(Mysql 篇)
聊聊 Python 資料處理全家桶(Sqlite 篇)
聊聊 Python 資料處理全家桶(Redis 篇)
聊聊 Python 資料處理全家桶(Memc 篇)
聊聊 Python 資料處理全家桶(Mongo 篇)

相關文章