python 配置文件讀寫

@(python)

[TOC]

前言

將代碼中的配置項抽取到配置文件中昏鹃,修改配置時不需要涉及到代碼修改欣簇,避免面對一堆令人抓狂的 magic number宣赔,極大的方便后期軟件的維護。

python 本身提供標準的配置讀寫模塊 configParse(python2汞斧,python3 修改為configparser),用于讀取 ini 格式的配置文件淆两。

[DEFAULT]
ServerAliveInterval = 45
Compression = yes

[topsecret.server.com]
Port = 50022
ForwardX11 = no

除了標準庫提供的模塊断箫,通過第三方模塊 pyYAML, 可以讀寫 yaml[1]式的配置文件秋冰。

本文介紹 python 通過 configParser 和 pyYAML 讀寫配置文件的方法仲义。

configParser

Note The ConfigParser module has been renamed to configparser in Python 3. The 2to3 tool will automatically adapt imports when converting your sources to Python 3.

python2 和 python3 中此模塊有些許不同,舊代碼可以通過工具進行轉(zhuǎn)換剑勾。
目前來說埃撵,python2 在項目中仍有使用,所以以下對在 python2 和 python3 下模塊的使用都進行介紹虽另。

python2 - ConfigParser

在ConfigParser 中提供了三個類:

  • RawConfigParser
  • ConfigParser
  • SafeConfigParser
    三個以此在前者的基礎進行擴展暂刘,接口提供額外可選參數(shù),提供更加復雜的功能捂刺,主要差別應該體現(xiàn)在對 %(value_name)s進行參數(shù)替換(value_name 為同section或者[DEFAULT]中的其他變量名才行)

這里使用的默認配置文件 default.cfg 內(nèi)容如下:

[DEFAULT]
default_name = lcd

[Section1]
an_int = 15
a_bool = true
a_float = 3.1415
baz = fun
bar = Python
foo = %(bar)s is %(baz)s!
name = s1_%(default_name)s   ; DEFAULT section's value

基本讀寫

使用 RawConfigParser 實現(xiàn)配置文件的基本的讀寫操作谣拣。

import ConfigParser

test_cfg = "./default.cfg"
config_raw = ConfigParser.RawConfigParser()
config_raw.read(test_cfg)

# 讀取配置文件中 [DEFAULT]
defaults = config_raw.defaults()
print defaults

# 讀取指定section下的value值
a_float = config_raw.getfloat('Section1', 'a_float')
print "-- number : %f type is : %s"%(a_float ,type(a_float))

# 設置指定section下的value值
# 此時沒有寫入文件,保存在內(nèi)存實例中
a_float = 2.14159
config_raw.set('Section1', 'a_float', a_float)
a_float = config_raw.getfloat('Section1', 'a_float')
print "-- number : %f type is : %s"%(a_float ,type(a_float))

# 讀取帶有參數(shù)替換模板的變量族展,但是沒有替換參數(shù)
print "-- RawConfigParser just get raw value"
str_foo = config_raw.get('Section1', 'foo')
print str_foo

對應不同數(shù)據(jù)類型森缠,除了調(diào)用get()獲取配置文件中的原始內(nèi)容,還可以使用對應的接口仪缸,getint, getboolean, 其中贵涵,布爾值 True 對應的是 1、yes恰画、true 和 on宾茂, False 對應 0、no拴还、false 和 off跨晴。

運行結果

OrderedDict([('default_name', 'lcd')])
-- number : 3.141500 type is : <type 'float'>
-- number : 2.141590 type is : <type 'float'>
-- RawConfigParser just get raw value
%(bar)s is %(baz)s!

參數(shù)替換

相比 RawConfigParser, 對于配置文件中foo = %(bar)s is %(baz)s! 這種格式的變量片林,在讀取的時候如果想要取得替換后的值坟奥,需要使用類 ConfigParser 或者 SafeConfigParser 。
代碼如下

config = ConfigParser.ConfigParser()
config.read(test_cfg)

print "-- ConfigParser can get interpolation"
## get 接口添加參數(shù) raw拇厢,raw=1 時直接返回配置文件中的值,不做參數(shù)替換
## raw 默認為0晒喷,設置為0時孝偎,返回替換后的值
str_foo = config.get('Section1', 'foo', raw=1)
#等同 str_foo = config.get('Section1', 'foo', 1)
print str_foo
str_foo = config.get('Section1', 'foo')
print str_foo
str_foo = config.get('Section1', 'foo', 0)
print str_foo

print "-- After set a new value"
str_foo = "%(name)s is %(baz)s!"
config.set('Section1', 'foo', str_foo)
str_foo = config.get('Section1', 'foo', 1)
print str_foo
str_foo = config.get('Section1', 'foo')
print str_foo

## raw=0,返回替換后的值凉敲,替換的變量是在同 section 下或者 default section 中查找
str_foo = config.get('Section1', 'name')
print str_foo

## 接口還有另外一個可選參數(shù) vars,
## 設置后衣盾,查詢配置 values 時寺旺,會優(yōu)先從vars這個{}尋找匹配的key返回
## 沒有再去尋找配置文件中的。
print "-- use default value if pass by vars={}"
a_float = config.get('Section1', 'a_float1', vars={'a_float1':'0.01'})
print "-- number : %f type is : %s"%(float(a_float) ,type(a_float))

運行結果

-- ConfigParser can get interpolation
%(bar)s is %(baz)s!
Python is fun!
Python is fun!
-- After set a new value
%(name)s is %(baz)s!
s1_lcd is fun!
s1_lcd
-- use default value if pass by vars={}
-- number : 0.010000 type is : <type 'str'>

使用默認參數(shù)

有些配置參數(shù)有時候配置文件中并沒有設置势决,此時程序中應該有對應的默認值阻塑,當找配置文件中查找不到時,使用配置值果复。注意和上一小節(jié)設置 vars={}不同陈莽,此處是優(yōu)先返回配置文件的值,沒有才返回設置的默認值虽抄,上面則相反走搁。

如下

## 設置默認值 name : default_name
config = ConfigParser.ConfigParser({'name' : 'default_name'})
config.readfp(open('./default.cfg'))
    
# 讀取存在的配置值,返回的是配置文件中的值
str_foo = config.get('Section1', 'name')
print str_foo
print "-- use default value"
config.remove_option('Section1', 'name')
# 讀取不存在的配置值迈窟,返回設置的默認值
str_foo = config.get('Section1', 'name')
print str_foo

運行結果

s1_lcd
-- use default value
default_name

使用默認配置文件

程序配置時私植,可以設置多個配置文件,并按照一定的優(yōu)先級使用相應的配置文件车酣,比如系統(tǒng)默認有個配置文件曲稼,不同的用戶下又使用不同的配置文件,程序運行時優(yōu)先使用用戶配置文件中的配置參數(shù)湖员,如果用戶配置文件不存在或者對應參數(shù)沒有設置贫悄,再讀取系統(tǒng)默認配置文件中的參數(shù)值。
此處破衔,默認配置文件是開頭提供的 default.cfg

另新加兩個配置文件:

user1.cfg

[DEFAULT]
default_name = user1

[Section1]
name = s1_%(default_name)s   ; DEFAULT section's value

user2.cfg

[DEFAULT]
default_name = user1

[Section1]
name = s1_%(default_name)s   ; DEFAULT section's value

我們希望清女,參數(shù)使用優(yōu)先級按照 user3.cfg > uer2.cfg > user1.cfg > default.cfg 使用
實現(xiàn)方式如下:

config = ConfigParser.ConfigParser()
## 設置默認的配置文件
## 注意此文件不存在會raise異常
config.readfp(open('./default.cfg'))
## 設置可選配置文件,最后優(yōu)先級最高晰筛,文件不存在則忽略
config.read(['./user1.cfg', './user2.cfg', './user3.cfg'])
# readfp 必須先調(diào)用后才能調(diào)用read嫡丙,否則read中都打不開,會報錯
# config.read(['./user11111111.cfg', './user22222222.cfg'])

## 可選文件中找不到的參數(shù)读第,在default中查找
an_int = config.getint('Section1', 'an_int')
print "-- number : %f type is : %s"%(an_int ,type(an_int))

## 使用可選文件中存在的參數(shù)
str_foo = config.get('Section1', 'name')
print str_foo

運行結果

-- number : 15.000000 type is : <type 'int'>
s1_user2

默認文件需要存在曙博,運行時加載失敗會報錯共屈,其他可選設置文件如果找不到勉吻,直接忽略。

python3 - configparser

可能考慮兼容性窃判,前面 python2 中實現(xiàn)的三個類在 python3 中依然支持吴汪。對于 python2 提供的參考上一節(jié)內(nèi)容惠窄,接下面我們看看 python3 的使用。

基本讀寫

同 python2 差不多漾橙,加載配置文件后可以通過諸如 get, getint的接口讀取參數(shù)值杆融,也可以像讀取 dict 一樣讀取配置參數(shù)。

讀取的配置文件example.ini 如下

[DEFAULT]
serveraliveinterval = 45
compression = yes
compressionlevel = 9
forwardx11 = yes

[bitbucket.org]
user = hg 
;comment
#comment 

[topsecret.server.com]
port = 50022
forwardx11 = no

使用接口讀取上述配置文件內(nèi)容

import configparser

config = configparser.ConfigParser()
print("- Empty config %s"%config.sections())

print("- Load config file")
config.read("./example.ini")
## 此處返回的sections list不包括 default
print("> config sections : %s"%config.sections()) 
print('bitbucket.org' in config )  ## 判斷配置文件中是否存在該 section
print("> Load config file is :")

for section in config.keys():
    print("[{s}]".format(s=section))
    for key in config[section]:
        print("{k} = {v}".format(k=key, v=config[section][key]))

## 如訪問 dict 一樣讀取配置內(nèi)容
print("\n- Get value like dict :user =  %s"%config['bitbucket.org']['user'])
conf_bitbucket = config['bitbucket.org']
print(conf_bitbucket['user'])

"""
The DEFAULT section which provides default values for all other sections"""
print("\n- DEFAULT Section")
## default 是所有section的默認設置霜运,備胎...
for key in config['bitbucket.org']: print(key)
print("> Get default value : forwardx11 = %s\n"%config['bitbucket.org']['forwardx11'])

## 讀取不同數(shù)據(jù)類型的配置參數(shù)
print("\n- Support datatypes")
forwardx11 = config['bitbucket.org'].getboolean('forwardx11')
int_port = config.getint('topsecret.server.com', 'port')
float_port = config.getfloat('topsecret.server.com', 'port')
print("> Get int port = %d type : %s"%(int_port, type(int_port)))
print("> Get float port = %f type : %s"%(float_port, type(float_port)))

運行結果如下:

- Empty config []
- Load config file
> config sections : ['bitbucket.org', 'topsecret.server.com']
True
> Load config file is :
[DEFAULT]
serveraliveinterval = 45
compression = yes
compressionlevel = 9
forwardx11 = yes
[bitbucket.org]
user = hg
serveraliveinterval = 45
compression = yes
compressionlevel = 9
forwardx11 = yes
[topsecret.server.com]
port = 50022
forwardx11 = no
serveraliveinterval = 45
compression = yes
compressionlevel = 9

- Get value like dict :user =  hg
hg

- DEFAULT Section
user
serveraliveinterval
compression
compressionlevel
forwardx11
> Get default value : forwardx11 = yes


- Support datatypes
> Get int port = 50022 type : <class 'int'>
> Get float port = 50022.000000 type : <class 'float'>

默認返回

在讀取配置參數(shù)時脾歇,設置如果在配置文件中查找不到指定值蒋腮,則默認返回的值。
在指定 section 和 default 中都找不到查找的值藕各,就會直接返回設置的 fallback池摧, 而不是 raise 錯誤。

print("\n- Return Fallback")
print("> Get value user = %s"%(config.get('bitbucket.org', 'user')))
print("> Get value user = %s"%(config.get('bitbucket.org', 'user', fallback="fallback_name")))
print("> Get value forwardx11 = %s"%(config.getboolean('bitbucket.org', 'forwardx11', fallback=False)))
print("> Get value forwardx22 = %s"%(config.getboolean('bitbucket.org', 'forwardx22', fallback=False)))
print("> Get value user2 = %s"%(config.get('bitbucket.org', 'user2', fallback="fallback_name")))

運行結果如下:

- Return Fallback
> Get value user = hg
> Get value user = hg
> Get value forwardx11 = True
> Get value forwardx22 = False
> Get value user2 = fallback_name

參數(shù)替換

在 python2 中提到的參數(shù)替換激况,pyton3 中默認使用的 BasicInterpolation(), 直接支持作彤,在上面就提到,這種替換誉碴,變量必須是同個 section(包括default)宦棺,如果要使用到其他 section 的參數(shù),就需要使用 ExtendedInterpolation()黔帕,并且代咸,語法上會有些許不同。

如下成黄,basic_interpolation.ini 是基礎的替換配置文件呐芥,和 python2 一樣

[Paths]
home_dir: /Users
my_dir: %(home_dir)s/lumberjack
my_pictures: %(my_dir)s/Pictures

而以下這個,擴展到參數(shù)可以使用不同的 section, 在 extended_interpolation.ini 中奋岁,替換的參數(shù)寫法是 ${section_name: value_name}

[Common]
home_dir: /Users
library_dir: /Library
system_dir: /System
macports_dir: /opt/local

[Frameworks]
Python: 3.2
path: ${Common:system_dir}/Library/Frameworks/

[Arthur]
nickname: Two Sheds
last_name: Jackson
my_dir: ${Common:home_dir}/twosheds
my_pictures: ${my_dir}/Pictures
python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python}

對以上兩個配置文件進行讀取思瘟,如下代碼

print("\n- BasicInterpolation")
#default : config = configparser.ConfigParser(interpolation=configparser.BasicInterpolation())
## 默認使用的 interpolation 就是 BasicInterpolation()
config.read("./basic_interpolation.ini")
print("> Get raw value %s"%(config.get('Paths', 'my_dir', raw = 1)))
print("> Get value %s"%(config.get('Paths', 'my_dir', raw = 0)))


print("\n- ExtendedInterpolation - other sections")
config = configparser.ConfigParser(interpolation=configparser.ExtendedInterpolation())
config.read("./extended_interpolation.ini")
print("> Get raw value %s"%(config.get('Arthur', 'python_dir', raw = 1)))
print("> Get value %s"%(config.get('Arthur', 'python_dir', raw = 0)))

運行結果 :

- BasicInterpolation
> Get raw value %(home_dir)s/lumberjack
> Get value /Users/lumberjack

- ExtendedInterpolation - other sections
> Get raw value ${Frameworks:path}/Python/Versions/${Frameworks:Python}
> Get value /System/Library/Frameworks//Python/Versions/3.2

pyYAML

jason

參考


  1. http://www.ruanyifeng.com/blog/2016/07/yaml.html?f=tt ?

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市闻伶,隨后出現(xiàn)的幾起案子滨攻,更是在濱河造成了極大的恐慌,老刑警劉巖蓝翰,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件光绕,死亡現(xiàn)場離奇詭異,居然都是意外死亡畜份,警方通過查閱死者的電腦和手機诞帐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來爆雹,“玉大人停蕉,你說我怎么就攤上這事「铺” “怎么了慧起?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長册倒。 經(jīng)常有香客問我完慧,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任屈尼,我火速辦了婚禮,結果婚禮上拴孤,老公的妹妹穿的比我還像新娘脾歧。我一直安慰自己,他們只是感情好演熟,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布鞭执。 她就那樣靜靜地躺著,像睡著了一般芒粹。 火紅的嫁衣襯著肌膚如雪兄纺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天化漆,我揣著相機與錄音估脆,去河邊找鬼。 笑死座云,一個胖子當著我的面吹牛疙赠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播朦拖,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼圃阳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了璧帝?” 一聲冷哼從身側響起捍岳,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎睬隶,沒想到半個月后锣夹,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡理疙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年晕城,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片窖贤。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡砖顷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出赃梧,到底是詐尸還是另有隱情滤蝠,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布授嘀,位于F島的核電站物咳,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蹄皱。R本人自食惡果不足惜览闰,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一芯肤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧压鉴,春花似錦崖咨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至婉宰,卻和暖如春歌豺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背心包。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工类咧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人谴咸。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓轮听,卻偏偏與公主長得像,于是被迫代替她去往敵國和親岭佳。 傳聞我的和親對象是個殘疾皇子血巍,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn)珊随,斷路器述寡,智...
    卡卡羅2017閱讀 134,599評論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,748評論 6 342
  • 國家電網(wǎng)公司企業(yè)標準(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 10,869評論 6 13
  • 一、Nagios簡介 Nagios是一款開源的電腦系統(tǒng)和網(wǎng)絡監(jiān)視工具叶洞,能有效監(jiān)控Windows鲫凶、Linux和Uni...
    1b3bd36d9d21閱讀 8,140評論 3 13
  • 今天和媽媽聊天,后來媽媽把以前的經(jīng)歷衩辟,所受的苦難全部給我講出來螟炫,因為覺得我也即將為人母了,一方面想用自己的經(jīng)歷告誡...
    王小蝸閱讀 140評論 0 0