ConfigParser में सूची


182

सामान्य कॉन्फ़िगरपार्सर उत्पन्न फ़ाइल इस तरह दिखती है:

[Section]
bar=foo
[Section 2]
bar2= baz

अब, उदाहरण के लिए, सूचियों को अनुक्रमित करने का एक तरीका है:

[Section 3]
barList={
    item1,
    item2
}

संबंधित प्रश्न: प्रति अनुभाग पायथन का कॉन्फिगरेशन अद्वितीय कुंजी

जवाबों:


142

सूची को एक सीमांकित स्ट्रिंग में पैक करने और फिर कॉन्फ़िगरेशन से स्ट्रिंग प्राप्त करने के बाद इसे अनपैक करने से आपको रोकना कुछ भी नहीं है। यदि आपने इसे इस तरह से किया है तो आपका कॉन्फिगर सेक्शन ऐसा लगेगा:

[Section 3]
barList=item1,item2

यह सुंदर नहीं है, लेकिन यह सबसे सरल सूचियों के लिए कार्यात्मक है।


2
और यदि आपको जटिल सूची मिली है, तो आप इस प्रश्न का उल्लेख कर सकते हैं: stackoverflow.com/questions/330900/… :-)
जॉन फोहे

अच्छा समाधान है, लेकिन यह कैसे करें यदि कोई संभावित परिसीमन नहीं है जो आप गारंटी दे सकते हैं कि सूची आइटम के अंदर दिखाई नहीं देगा ???
wim

@ मेरा उत्तर देखें, आप सीमांकक के रूप में \ n उपयोग कर सकते हैं
पीटर स्मिट

@wim आपको सीमांकक चरित्र से बचने का एक तरीका लागू करने की आवश्यकता होगी यदि यह एक कानूनी चरित्र हो सकता है। (और भागने के लिए आप जो भी चरित्र का उपयोग करते हैं उससे बचने का एक तरीका।)
jamesdlin

यदि किसी सूची में एक ही तत्व हो तो क्या होगा?
सेरोगो मफरा

223

थोड़ा देर से, लेकिन शायद कुछ के लिए मददगार। मैं विन्यासकर्ता और JSON के संयोजन का उपयोग कर रहा हूं:

[Foo]
fibs: [1,1,2,3,5,8,13]

बस इसके साथ पढ़ें:

>>> json.loads(config.get("Foo","fibs"))
[1, 1, 2, 3, 5, 8, 13]

यदि आपकी सूची लंबी है तो आप भी लाइनें तोड़ सकते हैं (धन्यवाद @ पीटर-स्मिट):

[Bar]
files_to_check = [
     "/path/to/file1",
     "/path/to/file2",
     "/path/to/another file with space in the name"
     ]

बेशक मैं सिर्फ JSON का उपयोग कर सकता था, लेकिन मुझे लगता है कि विन्यास फाइल बहुत अधिक पठनीय है, और [DEFAULT] अनुभाग बहुत आसान है।


1
यह भयानक है क्योंकि यह स्वचालित रूप से "कास्ट" मान करता है जो उपयोगी हो सकता है यदि आप पहले से प्रकार नहीं जानते हैं।
21GB पर LeGBT

मुझे यह विचार पसंद है, लेकिन मैं इसे केवल संख्याओं की सूची के साथ काम करने के लिए प्राप्त कर सकता हूं। उद्धरण चिह्न मदद नहीं करते हैं। अजीब। आगे बढ़ते रहना।
rsaw

5
आपको उनके लिए काम करने के लिए स्ट्रिंग्स के लिए ["a", "b", "c"] रखना पड़ेगा। मेरे लिए, यह संख्याओं के लिए क्लिक करता है लेकिन जैसा कि cfg फाइलें ज्यादातर संपादन योग्य हैं - "" जोड़ना हर समय एक दर्द है। मैं इसके बजाय अल्पविराम का उपयोग करता हूं और फिर इसे विभाजित कर देता हूं।
सौरभ हिरानी

केवल मानक पुस्तकालय का उपयोग करके एक सुरुचिपूर्ण समाधान। टिप्पणियाँ और json का उपयोग करने में सक्षम होने के लिए अच्छा है।
wi1

कच्चे तार के लिए यह कैसे काम करेगा, उदा key5 : [r"abc $x_i$", r"def $y_j$"]? वे त्रुटि को json.decoder.JSONDecodeError: Expecting value: line 1 column 2 (char 1)
बढ़ाते हैं

101

इस पार्टी में देर से आ रहा है, लेकिन मैंने हाल ही में एक सूची के लिए एक कॉन्फ़िगर फ़ाइल में एक समर्पित अनुभाग के साथ इसे लागू किया है:

[paths]
path1           = /some/path/
path2           = /another/path/
...

और config.items( "paths" )पथ की वस्तुओं की पुनरावृति सूची प्राप्त करने के लिए उपयोग करना, जैसे:

path_items = config.items( "paths" )
for key, path in path_items:
    #do something with path

आशा है कि यह इस प्रश्न को समझने में अन्य लोगों की मदद करता है;)


3
मुझे यह समाधान पसंद है, क्योंकि आप ; commentपूरी सूची को फिर से लिखने के बिना सूची से कुछ आइटम बाहर कर सकते हैं।
wim

1
+1, लेकिन अगर आप ऐसा करते हैं, तो बस इस्तेमाल करने में भी सावधानी बरतें key, क्योंकि कॉन्फिगरेशन ऐसे सभी कीज को लोअर केस में बदल देता है
एलेक्स डीन

4
@AlexDean आप OptionPform = str को सेट करके कैमपलेस को छोड़ने के लिए configParser को सेटअप कर सकते हैं। उदाहरण: config = ConfigParser.SafeConfigParser() config.optionxform = str फिर मामला अकेला छोड़ दिया जाएगा
कैमरून गुडेल

@ हेनरी कुक क्या आपने परीक्षण किया है कि जब एक कुंजी कई बार सूचीबद्ध होती है?
DevPlayer

1
@DevPlayer बहु-कुंजी उपयोग के साथ आपको केवल अंतिम मूल्य मिलता है। (अन्य पाठकों के लाभ के लिए 2 वर्ष पुरानी टिप्पणी का जवाब)
मार्सिन के

63

एक बात बहुत से लोगों को पता नहीं है कि मल्टी-लाइन कॉन्फ़िगरेशन-वैल्यू की अनुमति है। उदाहरण के लिए:

;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

स्रोत

यदि मैं आपके लिए यह एक सामान्य बात है, तो शायद, मैं कॉन्फ़िगरासर का विस्तार करूंगा:

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)]

ध्यान दें कि इस तकनीक का उपयोग करते समय कुछ बातों का ध्यान रखना चाहिए

  1. आइटम के साथ शुरू होने वाली नई लाइनें व्हॉट्सएप से शुरू होनी चाहिए (उदाहरण के लिए स्पेस या टैब)
  2. व्हाट्सएप से शुरू होने वाली सभी निम्न पंक्तियों को पिछली वस्तु का हिस्सा माना जाता है। इसके अलावा, अगर इसका कोई चिन्ह है या यदि यह a से शुरू होता है; व्हाट्सएप के बाद।

.splitlines()इसके बजाय आप का उपयोग क्यों करते हैं .split()? प्रत्येक के डिफ़ॉल्ट व्यवहार का उपयोग करते हुए, विभाजन स्पष्ट रूप से बेहतर है (खाली लाइनों को फ़िल्टर करता है)। जब तक मैं कुछ याद कर रहा हूँ ...
rsaw

7
सभी व्हाट्सएप पर .split () टूट जाता है (जब तक कि कोई विशिष्ट वर्ण नहीं दिया जाता है), सभी नए वर्णों पर .plitlines () टूट जाता है।
पीटर स्मिट

अह्ह्ह अच्छी बात। मैंने इस बारे में नहीं सोचा था कि मेरे मूल्यों में से कोई भी रिक्त स्थान नहीं था।
rsaw

38

यदि आप सूची में शाब्दिक रूप से उत्तीर्ण होना चाहते हैं तो आप इसका उपयोग कर सकते हैं:

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()? मुझे लगता है कि उत्तरार्द्ध अधिक सुरक्षा प्रदान करता है, नहीं?
रायलूओ

2
मैं इसे देखना और इसका उदाहरण देना पसंद करूंगा, इस थ्रेड का जवाब देने के लिए स्वतंत्र महसूस करें यदि आपको लगता है कि यह मदद करेगा, हालांकि आपकी टिप्पणी अपने आप में एक अच्छा सवाल है। मैंने जो उत्तर दिया, वह कॉन्फिगरप्रैसर की सूचियों की खपत को आसान बनाता है इसलिए एप्स का उपयोग करने के गुणन को दूर करने वाला ऐप आंतरिक है। मैं बिना संदर्भ के इसके "secuity" मूल्य पर टिप्पणी नहीं कर सकता था।
पायथनटैस्टर

मैं शाब्दिक_केवल का उपयोग करने में सावधान रहूँगा जो कि = के बाद अजगर स्ट्रिंग की उम्मीद करता है या इसलिए: आप अब उपयोग नहीं कर सकते हैं जैसे कि path1 = / some / path / but path1 = '/ some / path /'
vldbnc

21

के लिए kwarg का कोई उल्लेख नहीं हैconvertersConfigParser()इनमें से किसी भी उत्तर के था बल्कि निराशाजनक था।

दस्तावेज़ीकरण के अनुसार आप एक शब्दकोश पारित कर सकते हैं जो 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']

यह मेरा व्यक्तिगत पसंदीदा है क्योंकि कोई उपवर्ग आवश्यक नहीं है और मुझे जेएसएन या एक सूची को पूरी तरह से लिखने के लिए अंतिम उपयोगकर्ता पर भरोसा करने की आवश्यकता नहीं है ast.literal_eval


15

मैं इसका उपभोग करने के लिए यहाँ उतरा ...

[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']

हो सकता है कि यह ओपी के सवाल का ठीक-ठीक जवाब न दे, लेकिन कुछ लोगों की तलाश का साधारण जवाब हो सकता है।


2
मैंने सोचा था कि डिक में था sorger@espionage.su! कोई आश्चर्य नहीं कि मेरा मेल उछलता रहे! > _ <
अगस्ता

1
4 साल बाद इस टिप्पणी को पढ़ना और ईस्टर अंडे
एक उत्सुक इंजीनियर

11

यह वही है जो मैं सूचियों के लिए उपयोग करता हूं:

फ़ाइल सामग्री कॉन्फ़िगर करें:

[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]

धन्यवाद।


यह वह है जिसे मैं वास्तव में धन्यवाद के लिए देख रहा था @LittleEaster
ashley

5

दूसरा तरीका, जो मुझे पसंद है, उदाहरण के लिए, मूल्यों को विभाजित करना है:

#/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 के रूप में लोड करने के लिए कोष्ठक में अपने मूल्यों को लपेटने की आवश्यकता से रोकती है।


हाय मिच, बाद के मामले में get_int ('first_row') का उपयोग करने के लिए अच्छे नहीं थे। विभाजन (',') के बजाय स्पष्ट रूप से इसे लूप करते समय इंट में बदलने के लिए?
गुइडो

2

विन्यास पार्सर द्वारा क्रमांकन के लिए केवल आदिम प्रकार का समर्थन किया जाता है। मैं उस तरह की आवश्यकता के लिए JSON या YAML का उपयोग करूंगा।


स्पष्टीकरण के लिए धन्यवाद, utku। एकमात्र समस्या यह है कि मैं फिलहाल बाहरी पैकेज का उपयोग नहीं कर सकता। मुझे लगता है कि मैं इसे संभालने के लिए एक साधारण वर्ग लिखने वाला हूं। मैं इसे अंततः साझा करूँगा।
पिस्ताचियो

आप पायथन का कौन सा संस्करण चला रहे हैं? JSON मॉड्यूल 2.6 के साथ शामिल है।
पैट्रिक हैरिंगटन

2

मैंने अतीत में भी यही समस्या का सामना किया था। यदि आपको अधिक जटिल सूचियों की आवश्यकता है, तो विन्यासकर्ता से विरासत में अपना स्वयं का पार्सर बनाने पर विचार करें। तब आप उस के साथ विधि प्राप्त कर लेंगे:

    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

इस समाधान के साथ आप अपनी कॉन्फ़िग फ़ाइल में शब्दकोशों को भी परिभाषित कर पाएंगे।

लेकिन सावधान रहना! यह उतना सुरक्षित नहीं है: इसका मतलब है कि कोई भी आपकी कॉन्फ़िग फ़ाइल के माध्यम से कोड चला सकता है। यदि सुरक्षा आपके प्रोजेक्ट में कोई समस्या नहीं है, तो मैं सीधे अजगर कक्षाओं को कॉन्फिग फाइलों के रूप में उपयोग करने पर विचार करूंगा। एक विन्यासकर्ता फ़ाइल की तुलना में निम्नलिखित बहुत अधिक शक्तिशाली और खर्च करने योग्य है:

class Section
    bar = foo
class Section2
    bar2 = baz
class Section3
    barList=[ item1, item2 ]

मैं ऐसा करने के बारे में सोच रहा था, हालाँकि: कॉन्फिगर वैल्यू को सेट अप क्यों नहीं किया गया है barList=item1,item2और फिर कॉल करें if value.find(',') > 0: return value.split(','), या बेहतर अभी तक, एप्लिकेशन को सभी कॉन्फिग ऑप्शन को लिस्ट के रूप में पार्स किया है, और बस .split(',')सब कुछ आँख बंद करके?
दरोगांस

1
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'

यह बहुत ही सरल विन्यास के पार्सिंग के लिए है, आप बिना वस्तु लौटे Parser, या पार्सर वर्ग द्वारा कहीं और किए गए पार्सिंग कार्य को फिर से कर रहे हैं, या तो बिना किसी वस्तु को परिवर्तित किए, सभी प्रकार के आउटपुट, बूल, और अन्य प्रकार प्राप्त करने की क्षमता खो देते हैं।


1

मैंने अपनी परियोजना में समान कार्य को मानों के बिना कुंजियों के साथ पूरा किया:

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

0

json.loads और ast.literal_eval काम करने लेकिन config भीतर सरल सूची भी वर्ग कोष्ठक लौटने तो बाइट के रूप में प्रत्येक चरित्र इलाज है लगता है ....

अगर विन्यास है fieldvalue = [1,2,3,4,5]

तब के स्थान पर config.read(*.cfg) config['fieldValue'][0]लौट रहा [है1


0

जैसा कि पीटर स्मिट ( https://stackoverflow.com/a/11866695/7424596) ने उल्लेख किया है ) , आप कॉन्फिगरेशन का विस्तार करना चाहते हैं, इसके अलावा, एक इंटरपोलर का उपयोग सूची में स्वचालित रूप से परिवर्तित करने के लिए किया जा सकता है।

तल पर संदर्भ के लिए आप कोड पा सकते हैं जो स्वचालित रूप से कॉन्फ़िगर को कॉन्फ़िगर करता है जैसे:

[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)

पीएस इंडेंटेशन के महत्व को ध्यान में रखें। जैसा कि configParser डॉक्टर स्ट्रिंग में पढ़ता है:

मान कई पंक्तियों को फैला सकते हैं, जब तक कि वे मूल्य की पहली पंक्ति की तुलना में अधिक गहरे नहीं होते हैं। पार्सर मोड के आधार पर, रिक्त लाइनों को बहु-मान के भागों के रूप में माना जा सकता है या अनदेखा किया जा सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.