โดยทั่วไป ConfigParser สร้างรูปลักษณ์ไฟล์เช่น:
[Section]
bar=foo
[Section 2]
bar2= baz
ตอนนี้มีวิธีการจัดทำดัชนีรายการเช่น:
[Section 3]
barList={
item1,
item2
}
คำถามที่เกี่ยวข้อง: คีย์ที่ไม่ซ้ำกันของ ConfigParser Python ต่อส่วน
โดยทั่วไป ConfigParser สร้างรูปลักษณ์ไฟล์เช่น:
[Section]
bar=foo
[Section 2]
bar2= baz
ตอนนี้มีวิธีการจัดทำดัชนีรายการเช่น:
[Section 3]
barList={
item1,
item2
}
คำถามที่เกี่ยวข้อง: คีย์ที่ไม่ซ้ำกันของ ConfigParser Python ต่อส่วน
คำตอบ:
ไม่มีอะไรหยุดคุณจากการบรรจุรายการลงในสตริงที่มีการคั่นแล้วคลายออกเมื่อคุณได้รับสตริงจากการกำหนดค่า หากคุณทำเช่นนี้ในส่วนกำหนดค่าของคุณจะมีลักษณะดังนี้:
[Section 3]
barList=item1,item2
มันไม่สวย แต่ใช้งานได้กับรายการที่ง่ายที่สุด
สายไปหน่อย แต่อาจมีประโยชน์สำหรับบางคน ฉันใช้การรวมกันของ ConfigParser และ JSON:
[Foo]
fibs: [1,1,2,3,5,8,13]
แค่อ่านด้วย:
>>> json.loads(config.get("Foo","fibs"))
[1, 1, 2, 3, 5, 8, 13]
คุณสามารถแบ่งบรรทัดหากรายการของคุณมีความยาว (ขอบคุณ @ peter-smit):
[Bar]
files_to_check = [
"/path/to/file1",
"/path/to/file2",
"/path/to/another file with space in the name"
]
แน่นอนฉันสามารถใช้ JSON ได้ แต่ฉันพบไฟล์กำหนดค่าที่สามารถอ่านได้มากขึ้นและส่วน [DEFAULT] มีประโยชน์มาก
key5 : [r"abc $x_i$", r"def $y_j$"]
? พวกเขายกข้อผิดพลาดjson.decoder.JSONDecodeError: Expecting value: line 1 column 2 (char 1)
มางานปาร์ตี้สายนี้ แต่ฉันเพิ่งนำสิ่งนี้ไปใช้กับส่วนเฉพาะในไฟล์ปรับแต่งสำหรับรายการ:
[paths]
path1 = /some/path/
path2 = /another/path/
...
และการใช้config.items( "paths" )
เพื่อรับรายการ iterable ของรายการเส้นทางเช่น:
path_items = config.items( "paths" )
for key, path in path_items:
#do something with path
หวังว่าจะช่วยให้ชาวบ้านคนอื่น ๆ Googling คำถามนี้;)
; comment
รายการออกบางอย่างจากรายการโดยไม่ต้องเขียนรายชื่อทั้งหมด
key
เนื่องจาก ConfigParser แปลงคีย์ดังกล่าวทั้งหมดเป็นตัวพิมพ์
config = ConfigParser.SafeConfigParser()
config.optionxform = str
แล้วกรณีที่จะถูกทิ้งไว้ตามลำพัง
สิ่งหนึ่งที่ผู้คนจำนวนมากไม่รู้คืออนุญาตให้กำหนดค่าหลายค่าได้ ตัวอย่างเช่น:
;test.ini
[hello]
barlist =
item1
item2
มูลค่าของconfig.get('hello','barlist')
ตอนนี้จะเป็น:
"\nitem1\nitem2"
ซึ่งคุณสามารถแยกด้วยวิธีแยกได้อย่างง่ายดาย (อย่าลืมกรองรายการที่ว่างเปล่า)
ถ้าเรามองไปที่กรอบใหญ่เช่นพีระมิดพวกเขาจะใช้เทคนิคนี้:
def aslist_cronly(value):
if isinstance(value, string_types):
value = filter(None, [x.strip() for x in value.splitlines()])
return list(value)
def aslist(value, flatten=True):
""" Return a list of strings, separating the input based on newlines
and, if flatten=True (the default), also split on spaces within
each line."""
values = aslist_cronly(value)
if not flatten:
return values
result = []
for value in values:
subvalues = value.split()
result.extend(subvalues)
return result
ตัวฉันเองฉันอาจจะขยาย ConfigParser ถ้านี่เป็นเรื่องปกติสำหรับคุณ:
class MyConfigParser(ConfigParser):
def getlist(self,section,option):
value = self.get(section,option)
return list(filter(None, (x.strip() for x in value.splitlines())))
def getlistint(self,section,option):
return [int(x) for x in self.getlist(section,option)]
ทราบว่ามีบางสิ่งที่ต้องระวังเมื่อใช้เทคนิคนี้
.splitlines()
แทน.split()
? เมื่อใช้พฤติกรรมเริ่มต้นของแต่ละการแบ่งจะดีกว่าอย่างชัดเจน (กรองบรรทัดว่าง) เว้นแต่ฉันหายไปบางสิ่งบางอย่าง ...
หากคุณต้องการส่งผ่านรายการอย่างแท้จริงคุณสามารถใช้:
ast.literal_eval()
สำหรับการกำหนดค่าตัวอย่างเช่น:
[section]
option=["item1","item2","item3"]
รหัสคือ:
import ConfigParser
import ast
my_list = ast.literal_eval(config.get("section", "option"))
print(type(my_list))
print(my_list)
เอาท์พุท:
<type'list'>
["item1","item2","item3"]
ast.literal_eval()
เมื่อเปรียบเทียบกับการใช้ (นิยมมากขึ้น) json.loads()
? ฉันคิดว่าอันหลังให้ความปลอดภัยมากกว่าใช่ไหม
ไม่มีการกล่าวถึงconverters
kwarg สำหรับConfigParser()
คำตอบใด ๆ เหล่านี้ค่อนข้างน่าผิดหวัง
ตามเอกสารคุณสามารถส่งพจนานุกรมไปConfigParser
ที่จะเพิ่มget
วิธีการสำหรับตัวแยกวิเคราะห์และส่วนพร็อกซี่ ดังนั้นสำหรับรายการ:
example.ini
[Germ]
germs: a,list,of,names, and,1,2, 3,numbers
ตัวอย่างโปรแกรมแยกวิเคราะห์:
cp = ConfigParser(converters={'list': lambda x: [i.strip() for i in x.split(',')]})
cp.read('example.ini')
cp.getlist('Germ', 'germs')
['a', 'list', 'of', 'names', 'and', '1', '2', '3', 'numbers']
cp['Germ'].getlist('germs')
['a', 'list', 'of', 'names', 'and', '1', '2', '3', 'numbers']
นี่คือรายการโปรดส่วนตัวของฉันเนื่องจากไม่จำเป็นต้องใช้คลาสย่อยและฉันไม่จำเป็นต้องพึ่งพาผู้ใช้เพื่อเขียน JSON หรือรายการที่สามารถตีความast.literal_eval
ได้อย่างสมบูรณ์
ฉันลงจอดที่นี่เพื่อใช้สิ่งนี้ ...
[global]
spys = richard.sorge@cccp.gov, mata.hari@deutschland.gov
คำตอบคือการแบ่งมันในจุลภาคและตัดช่องว่าง:
SPYS = [e.strip() for e in parser.get('global', 'spys').split(',')]
ในการรับผลรายการ:
['richard.sorge@cccp.gov', 'mata.hari@deutschland.gov']
อาจไม่ตอบคำถามของ OP แน่นอน แต่อาจเป็นคำตอบง่ายๆที่บางคนกำลังมองหา
sorger@espionage.su
! ไม่แปลกใจเลยที่อีเมลของฉันจะเด้ง > _ <
นี่คือสิ่งที่ฉันใช้สำหรับรายการ:
เนื้อหาไฟล์ปรับแต่ง:
[sect]
alist = a
b
c
รหัส:
l = config.get('sect', 'alist').split('\n')
มันใช้งานได้กับสตริง
ในกรณีของตัวเลข
เนื้อหาการกำหนดค่า:
nlist = 1
2
3
รหัส:
nl = config.get('sect', 'alist').split('\n')
l = [int(nl) for x in nl]
ขอบคุณ
อีกวิธีที่ฉันชอบคือการแยกค่าต่างๆเช่น:
#/path/to/config.cfg
[Numbers]
first_row = 1,2,4,8,12,24,36,48
สามารถโหลดเช่นนี้ลงในรายการสตริงหรือจำนวนเต็มดังนี้
import configparser
config = configparser.ConfigParser()
config.read('/path/to/config.cfg')
# Load into a list of strings
first_row_strings = config.get('Numbers', 'first_row').split(',')
# Load into a list of integers
first_row_integers = [int(x) for x in config.get('Numbers', 'first_row').split(',')]
วิธีนี้ป้องกันไม่ให้คุณต้องห่อค่าของคุณในวงเล็บเพื่อโหลดเป็น JSON
สนับสนุนชนิดดั้งเดิมเท่านั้นสำหรับการทำให้เป็นอนุกรมโดยตัวแยกวิเคราะห์การกำหนดค่า ฉันจะใช้ JSON หรือ YAML สำหรับความต้องการประเภทนั้น
ฉันประสบปัญหาเดียวกันในอดีต หากคุณต้องการรายการที่ซับซ้อนมากขึ้นให้พิจารณาสร้าง parser ของคุณเองโดยสืบทอดจาก ConfigParser จากนั้นคุณจะเขียนทับวิธี get ด้วย:
def get(self, section, option):
""" Get a parameter
if the returning value is a list, convert string value to a python list"""
value = SafeConfigParser.get(self, section, option)
if (value[0] == "[") and (value[-1] == "]"):
return eval(value)
else:
return value
ด้วยวิธีนี้คุณจะสามารถกำหนดพจนานุกรมในไฟล์ปรับแต่งของคุณได้
แต่ระวังด้วย! สิ่งนี้ไม่ปลอดภัย: หมายความว่าทุกคนสามารถเรียกใช้รหัสผ่านไฟล์ปรับแต่งของคุณได้ หากการรักษาความปลอดภัยไม่ใช่ปัญหาในโครงการของคุณฉันจะพิจารณาใช้คลาสหลามโดยตรงเป็นไฟล์กำหนดค่า ต่อไปนี้มีประสิทธิภาพและใช้งานได้มากกว่าไฟล์ ConfigParser:
class Section
bar = foo
class Section2
bar2 = baz
class Section3
barList=[ item1, item2 ]
barList=item1,item2
แล้วโทรif value.find(',') > 0: return value.split(',')
หรือดีกว่ายังมีแอปพลิเคชันแยกตัวเลือกการกำหนดค่าทั้งหมดเป็นรายการและ.split(',')
ทุกอย่างเพียงแค่สุ่มสี่สุ่มห้า?
import ConfigParser
import os
class Parser(object):
"""attributes may need additional manipulation"""
def __init__(self, section):
"""section to retun all options on, formatted as an object
transforms all comma-delimited options to lists
comma-delimited lists with colons are transformed to dicts
dicts will have values expressed as lists, no matter the length
"""
c = ConfigParser.RawConfigParser()
c.read(os.path.join(os.path.dirname(__file__), 'config.cfg'))
self.section_name = section
self.__dict__.update({k:v for k, v in c.items(section)})
#transform all ',' into lists, all ':' into dicts
for key, value in self.__dict__.items():
if value.find(':') > 0:
#dict
vals = value.split(',')
dicts = [{k:v} for k, v in [d.split(':') for d in vals]]
merged = {}
for d in dicts:
for k, v in d.items():
merged.setdefault(k, []).append(v)
self.__dict__[key] = merged
elif value.find(',') > 0:
#list
self.__dict__[key] = value.split(',')
ดังนั้นตอนนี้config.cfg
ไฟล์ของฉันซึ่งอาจมีลักษณะเช่นนี้:
[server]
credentials=username:admin,password:$3<r3t
loggingdirs=/tmp/logs,~/logs,/var/lib/www/logs
timeoutwait=15
สามารถแยกวิเคราะห์เป็นวัตถุขนาดเล็กพอสำหรับโครงการขนาดเล็กของฉัน
>>> import config
>>> my_server = config.Parser('server')
>>> my_server.credentials
{'username': ['admin'], 'password', ['$3<r3t']}
>>> my_server.loggingdirs:
['/tmp/logs', '~/logs', '/var/lib/www/logs']
>>> my_server.timeoutwait
'15'
นี่คือสำหรับการแยกอย่างรวดเร็วมากของ configs ง่ายคุณสูญเสียความสามารถทั้งหมดที่สามารถดึงข้อมูล ints, bools และประเภทอื่น ๆ ของการส่งออกโดยไม่ต้องเปลี่ยนทั้งวัตถุที่กลับมาจากParser
หรือใหม่ทำหน้าที่แยกประสบความสำเร็จโดยชั้น Parser อื่น ๆ
ฉันทำงานที่คล้ายกันในโครงการด้วยส่วนที่มีคีย์โดยไม่มีค่า:
import configparser
# allow_no_value param says that no value keys are ok
config = configparser.ConfigParser(allow_no_value=True)
# overwrite optionxform method for overriding default behaviour (I didn't want lowercased keys)
config.optionxform = lambda optionstr: optionstr
config.read('./app.config')
features = list(config['FEATURES'].keys())
print(features)
เอาท์พุท:
['BIOtag', 'TextPosition', 'IsNoun', 'IsNomn']
app.config:
[FEATURES]
BIOtag
TextPosition
IsNoun
IsNomn
json.loads
& ast.literal_eval
ดูเหมือนว่าจะทำงานได้ แต่รายการที่เรียบง่ายภายใน config กำลังปฏิบัติต่ออักขระแต่ละตัวเป็นไบต์ดังนั้นกลับมาเป็นวงเล็บเหลี่ยม ...
ความหมายถ้า config มี fieldvalue = [1,2,3,4,5]
จากนั้นconfig.read(*.cfg)
config['fieldValue'][0]
กลับมา[
แทนที่1
ตามที่ระบุไว้โดย Peter Smit ( https://stackoverflow.com/a/11866695/7424596 ) คุณอาจต้องการขยาย ConfigParser นอกจากนี้ Interpolator สามารถใช้ในการแปลงเป็นและจากรายการโดยอัตโนมัติ
สำหรับการอ้างอิงที่ด้านล่างคุณสามารถค้นหารหัสที่แปลงการกำหนดค่าโดยอัตโนมัติเช่น:
[DEFAULT]
keys = [
Overall cost structure, Capacity, RAW MATERIALS,
BY-PRODUCT CREDITS, UTILITIES, PLANT GATE COST,
PROCESS DESCRIPTION, AT 50% CAPACITY, PRODUCTION COSTS,
INVESTMENT, US$ MILLION, PRODUCTION COSTS, US ¢/LB,
VARIABLE COSTS, PRODUCTION COSTS, MAINTENANCE MATERIALS
]
ดังนั้นหากคุณขอรหัสคุณจะได้รับ:
<class 'list'>: ['Overall cost structure', 'Capacity', 'RAW MATERIALS', 'BY-PRODUCT CREDITS', 'UTILITIES', 'PLANT GATE COST', 'PROCESS DESCRIPTION', 'AT 50% CAPACITY', 'PRODUCTION COSTS', 'INVESTMENT', 'US$ MILLION', 'PRODUCTION COSTS', 'US ¢/LB', 'VARIABLE COSTS', 'PRODUCTION COSTS', 'MAINTENANCE MATERIALS']
รหัส:
class AdvancedInterpolator(Interpolation):
def before_get(self, parser, section, option, value, defaults):
is_list = re.search(parser.LIST_MATCHER, value)
if is_list:
return parser.getlist(section, option, raw=True)
return value
class AdvancedConfigParser(ConfigParser):
_DEFAULT_INTERPOLATION = AdvancedInterpolator()
LIST_SPLITTER = '\s*,\s*'
LIST_MATCHER = '^\[([\s\S]*)\]$'
def _to_list(self, str):
is_list = re.search(self.LIST_MATCHER, str)
if is_list:
return re.split(self.LIST_SPLITTER, is_list.group(1))
else:
return re.split(self.LIST_SPLITTER, str)
def getlist(self, section, option, conv=lambda x:x.strip(), *, raw=False, vars=None,
fallback=_UNSET, **kwargs):
return self._get_conv(
section, option,
lambda value: [conv(x) for x in self._to_list(value)],
raw=raw,
vars=vars,
fallback=fallback,
**kwargs
)
def getlistint(self, section, option, *, raw=False, vars=None,
fallback=_UNSET, **kwargs):
return self.getlist(section, option, int, raw=raw, vars=vars,
fallback=fallback, **kwargs)
def getlistfloat(self, section, option, *, raw=False, vars=None,
fallback=_UNSET, **kwargs):
return self.getlist(section, option, float, raw=raw, vars=vars,
fallback=fallback, **kwargs)
def getlistboolean(self, section, option, *, raw=False, vars=None,
fallback=_UNSET, **kwargs):
return self.getlist(section, option, self._convert_to_boolean,
raw=raw, vars=vars, fallback=fallback, **kwargs)
psเก็บไว้ในใจความสำคัญของการเยื้อง ในฐานะที่อ่านในสตริง Doc ConfigParser:
ค่าสามารถขยายหลายบรรทัดตราบใดที่มีการเยื้องลึกกว่าบรรทัดแรกของค่า ขึ้นอยู่กับโหมดของตัวแยกวิเคราะห์บรรทัดว่างอาจถูกถือว่าเป็นส่วนหนึ่งของค่าหลายบรรทัดหรือถูกละเว้น