ConfigParser'daki listeler


Yanıtlar:


142

Listeyi sınırlandırılmış bir dizeye paketlemenizi ve dizeyi config'ten aldığınızda paketini açmanızı engelleyen hiçbir şey yoktur. Bunu bu şekilde yaptıysanız, yapılandırma bölümünüz şöyle görünecektir:

[Section 3]
barList=item1,item2

Güzel değil ama çoğu basit liste için işlevsel.


2
Ve karmaşık listeleriniz varsa, bu soruya başvurabilirsiniz: stackoverflow.com/questions/330900/… :-)
John Fouhy

güzel bir çözüm, ancak garanti edemeyeceğiniz olası bir sınırlayıcı yoksa nasıl yapılır bir liste öğesinin içinde görünmez ???
wim

@wim Cevabımı görün, \ n sınırlayıcı olarak kullanabilirsiniz
Peter Smit

@wim Yasal bir karakter olabiliyorsa, sınırlayıcı karakterden kaçmanın bir yolunu uygulamanız gerekir. (Ve kaçmak için kullandığınız karakterden kaçmanın bir yolu.)
jamesdlin

Bir listenin tek bir öğesi varsa ne olur?
Sérgio Mafra

223

Ayrıca biraz geç, ama belki bazıları için yararlı. ConfigParser ve JSON bir arada kullanıyorum:

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

sadece şununla okuyun:

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

Listeniz uzunsa satırları bile kesebilirsiniz (teşekkürler @ peter-smit):

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

Tabii ki ben sadece JSON kullanabilirsiniz, ama ben çok daha okunabilir yapılandırma dosyaları bulmak ve [VARSAYILAN] Bölüm çok kullanışlı.


1
Önceden türleri bilmiyorsanız yararlı olabilecek değerleri otomatik olarak "yayınlar" çünkü harika.
LeGBT

Bu fikri seviyorum, ama sadece sayı listeleriyle çalışmasını sağlayabiliyorum. Tırnak işaretleri yardımcı olmaz. Tuhaf. Hareketli.
rsaw

5
Çalışması için dizgiler için ["a", "b", "c"] tuşlarına sahip olmanız gerekir. Benim için, bu sayıları tıklar, ancak cfg dosyaları çoğunlukla düzenlenebilir olduğundan - "" eklemek her zaman bir acıdır. Virgül kullanmayı ve sonra ayırmayı tercih ederim.
Saurabh Hirani

Yalnızca standart kütüphaneyi kullanan zarif bir çözüm. Yorum ve json kullanabilmek güzel.
wi1

Bu ham dizelerde nasıl çalışır, örneğin key5 : [r"abc $x_i$", r"def $y_j$"]? Hatayı yükseltiyorlarjson.decoder.JSONDecodeError: Expecting value: line 1 column 2 (char 1)
kingusiu

101

Bu partiye geç geliyor, ancak son zamanlarda bunu bir liste için bir yapılandırma dosyasında özel bir bölümle uyguladım:

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

ve config.items( "paths" )yol öğelerinin yinelenebilir bir listesini almak için kullanarak , şöyle:

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

Umarım bu diğer insanlara bu soruyu Google'da aramaya yardımcı olur;)


3
Bu çözümü beğendim, çünkü ; commenttüm listeyi yeniden yazmak zorunda kalmadan listeden belirli öğeleri çıkarabilirsiniz.
wim

1
+1, ancak bunu yaparsanız key, ConfigParser bu tür anahtarları küçük harfe dönüştürdüğü için de kullanmaya dikkat edin
Alex Dean

4
@AlexDean Configxarser seçeneğini optionxform = str ayarlayarak camelCase'i yerinde bırakacak şekilde ayarlayabilirsiniz. Örnek: config = ConfigParser.SafeConfigParser() config.optionxform = str O zaman dava yalnız bırakılacak
Cameron Goodale

@Henry Cooke Bir anahtar birden çok kez listelendiğinde bunu test ettiniz mi?
DevPlayer

1
@DevPlayer Çoklu tuş kullanımıyla yalnızca son değeri elde edersiniz. (diğer okuyucuların yararına 2 yıllık eski yoruma yanıt)
Marcin K

63

Birçok insanın bilmediği bir şey, çok satırlı yapılandırma değerlerine izin verilmesidir. Örneğin:

;test.ini
[hello]
barlist = 
    item1
    item2

Değeri config.get('hello','barlist')şu şekilde olacak:

"\nitem1\nitem2"

Hangi kolayca splitlines yöntemi ile bölmek (boş öğeleri filtre unutmayın).

Piramit gibi büyük bir çerçeveye bakarsak, bu tekniği kullanıyorlar:

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

Kaynak

Kendim, bu sizin için ortak bir şeyse ben belki ConfigParser uzatmak olacaktır:

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

Bu tekniği kullanırken dikkat edilmesi gereken birkaç nokta olduğunu unutmayın

  1. Öğe olan yeni satırlar boşlukla başlamalıdır (örneğin boşluk veya sekme)
  2. Beyaz boşlukla başlayan aşağıdaki tüm satırlar, bir önceki öğenin parçası olarak kabul edilir. Ayrıca = işaretine sahipse veya a ile başlıyorsa; boşluk takibi.

Neden .splitlines()yerine kullanıyorsun .split()? Her birinin varsayılan davranışını kullanarak, bölünme açıkça üstündür (boş satırları filtreler). Bir şey eksik olmadıkça ...
20'de testere

7
.split () tüm boşluklarda (belirli bir karakter verilmedikçe), .splitlines () tüm yeni satır karakterlerinde kırılır.
Peter Smit

Ahhh iyi bir nokta. Hiçbir değerimin boşluk olmadığı için bunu düşünmedim.
testere

38

İsterseniz tam anlamıyla bir listede geçmesine sonra kullanabilirsiniz:

ast.literal_eval()

Örneğin yapılandırma:

[section]
option=["item1","item2","item3"]

Kod:

import ConfigParser
import ast

my_list = ast.literal_eval(config.get("section", "option"))
print(type(my_list))
print(my_list)

çıktı:

<type'list'>
["item1","item2","item3"]

Bu durumda, ast.literal_eval()(tartışmasız daha popüler) ile karşılaştırırken kullanmanın avantajı json.loads()nedir? Sanırım ikincisi daha fazla güvenlik sağlıyor, değil mi?
RayLuo

2
Bunu görmek ve örnek isterim, yorumunuz kendi başına iyi bir soru yapacak olsa da, yardımcı olacağını düşünüyorsanız, bu konuya bir cevap eklemek için çekinmeyin. Verdiğim cevap, ConfigParser listelerinin tüketimini kolaylaştırıyor, bu nedenle regex kullanımının karmaşıklığını kaldırarak uygulamaya dahili. Bağlam olmadan onun "güvenlik" değeri hakkında yorum yapamadım.
PythonTester

Sonra = veya: sonra artık kullanamazsınız örneğin path1 = / bazı / yol / ama path1 = '/ bazı / yol /'
vldbnc 19:19

21

Bu cevapların herhangi birinde converterskwarg'danConfigParser() bahsetmek oldukça hayal kırıklığı yarattı.

Dokümantasyona göre, hem ayrıştırıcı hem de bölüm proxy'leri için ConfigParserbir getyöntem ekleyecek bir sözlük iletebilirsiniz . Bir liste için:

example.ini

[Germ]
germs: a,list,of,names, and,1,2, 3,numbers

Ayrıştırıcı örneği:

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

Hiçbir alt sınıflama gerekli olmadığından bu benim kişisel favorim ve mükemmel bir JSON veya yorumlanabilecek bir liste yazmak için bir son kullanıcıya güvenmek zorunda değilim ast.literal_eval.


15

Bunu tüketmek için buraya indim ...

[global]
spys = richard.sorge@cccp.gov, mata.hari@deutschland.gov

Cevap virgül üzerine bölmek ve boşlukları soymaktır:

SPYS = [e.strip() for e in parser.get('global', 'spys').split(',')]

Liste sonucu almak için:

['richard.sorge@cccp.gov', 'mata.hari@deutschland.gov']

OP'nin sorusuna tam olarak cevap vermeyebilir, ancak bazı insanların aradığı basit cevap olabilir.


2
Dick'in olduğunu sanıyordum sorger@espionage.su! Postalarımın sıçramasına şaşmamalı! > _ <
Augusta

1
4 yıl sonra bu yorumu okumak ve paskalya yumurtası kıkırdamak
meraklı bir mühendis

11

Listeler için kullandığım şey bu:

yapılandırma dosyası içeriği:

[sect]
alist = a
        b
        c

kod:

l = config.get('sect', 'alist').split('\n')

ipler için çalışır

sayılar olması durumunda

yapılandırma içeriği:

nlist = 1
        2
        3

kod:

nl = config.get('sect', 'alist').split('\n')
l = [int(nl) for x in nl]

Teşekkürler.


Bu aslında teşekkür aradığım şeydi @LittleEaster
ashley

5

Yani tercih ettiğim başka bir yol, sadece değerleri bölmektir, örneğin:

#/path/to/config.cfg
[Numbers]
first_row = 1,2,4,8,12,24,36,48

Aşağıdaki gibi dizeler veya tamsayılar listesine bu şekilde yüklenebilir:

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(',')]

Bu yöntem, JSON olarak yüklemek için değerlerinizi parantez içine almanıza gerek kalmasını önler.


Merhaba Mitch, ikinci durumda döngü sırasında açıkça int dönüştürmek yerine get_int ('first_row'). Split (',') kullanmak daha hoş olmaz mıydı?
Guido

2

Yapılandırma ayrıştırıcısı tarafından serileştirme için yalnızca ilkel türler desteklenir. Bu tür gereksinimler için JSON veya YAML kullanırdım.


açıklama için teşekkürler utku. tek sorun şu anda harici paketleri kullanamazsınız. bence bunun üstesinden gelmek için basit bir sınıf yazacağım. sonunda paylaşacağım.
pistacchio

Hangi Python sürümünü kullanıyorsunuz? JSON modülü 2.6 sürümüne dahildir.
Patrick Harrington

2

Geçmişte de aynı problemle karşılaştım. Daha karmaşık listelere ihtiyacınız varsa, ConfigParser'dan devralınarak kendi ayrıştırıcıyı oluşturmayı düşünün. Daha sonra get yönteminin üzerine yazarsınız:

    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

Bu çözüm ile yapılandırma dosyanızda da sözlükler tanımlayabilirsiniz.

Ama dikkat et! Bu kadar güvenli değil: Bu, herkesin yapılandırma dosyanız üzerinden kod çalıştırabileceği anlamına gelir. Güvenlik projenizde bir sorun değilse, doğrudan python sınıflarını yapılandırma dosyaları olarak kullanmayı düşünürüm. Aşağıdakiler bir ConfigParser dosyasından çok daha güçlü ve harcanabilir:

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

Ancak, bunu yapmayı düşünüyordum: niçin yapılandırma değerleri gibi ayarlanıp barList=item1,item2sonra çağrılmıyor if value.find(',') > 0: return value.split(','), ya da daha iyisi, uygulama tüm yapılandırma seçeneklerini listeler olarak ayrıştırmadı ve sadece .split(',')her şey körü körüne?
Droogans

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(',')

Şimdi benim config.cfgdosya, hangi gibi görünebilir:

[server]
credentials=username:admin,password:$3<r3t
loggingdirs=/tmp/logs,~/logs,/var/lib/www/logs
timeoutwait=15

Küçük projem için yeterince ayrıntılı nesnelere ayrıştırılabilir.

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

Bu, basit yapılandırmaların çok hızlı ayrıştırılması içindir, döndürülen nesneyi dönüştürmeden Parserveya başka bir yerde Parser sınıfı tarafından gerçekleştirilen ayrıştırma işini yeniden yapmadan, içe, boole ve diğer çıktı türlerini alma yeteneğini kaybedersiniz .


1

Projemde benzer görevleri, değerleri olmayan anahtarları olan bölümle tamamladım:

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)

Çıktı:

['BIOtag', 'TextPosition', 'IsNoun', 'IsNomn']

app.config:

[FEATURES]
BIOtag
TextPosition
IsNoun
IsNomn

0

json.loads & ast.literal_eval çalışıyor gibi görünüyor ama config içinde basit liste her karakter bayt olarak tedavi böylece köşeli ayraç bile dönen ....

eğer yapılandırma varsa fieldvalue = [1,2,3,4,5]

Daha sonra config.read(*.cfg) config['fieldValue'][0]dönen [yerine1


0

Peter Smit tarafından belirtildiği gibi ( https://stackoverflow.com/a/11866695/7424596 ) ConfigParser'ı genişletmek isteyebilirsiniz, ek olarak, otomatik olarak listeye ve listeden dönüştürmek için bir Interpolator kullanılabilir.

Alttaki referans için yapılandırmayı otomatik olarak dönüştüren kodu bulabilirsiniz:

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

Yani anahtar talep ederseniz:

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

Kod:

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 girinti önemini unutmayın. ConfigParser doc dizesinde okunduğu gibi:

Değerler, değerin ilk satırından daha derin girintili oldukları sürece birden çok satıra yayılabilir. Ayrıştırıcının moduna bağlı olarak, boş satırlar çok satırlı değerlerin parçaları olarak değerlendirilebilir veya yok sayılabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.