Jak czytać i pisać plik INI za pomocą Python3?

118

Muszę czytać, pisać i tworzyć plik INI w Python3.

FILE.INI

default_path = "/path/name/"
default_file = "file.txt"

Plik Pythona:

#    Read file and and create if it not exists
config = iniFile( 'FILE.INI' )

#    Get "default_path"
config.default_path

#    Print (string)/path/name
print config.default_path

#    Create or Update
config.append( 'default_path', 'var/shared/' )
config.append( 'default_message', 'Hey! help me!!' )

UPDATED FILE.INI

default_path    = "var/shared/"
default_file    = "file.txt"
default_message = "Hey! help me!!"
Olaf
źródło
5
A co z docs.python.org/library/configparser.html ?
Jakiś koleś programista
2
A co powiesz na stackoverflow.com/a/3220891/716118 ?
voithos,
właściwy plik ini wymaga nagłówka sekcji, takiego jak [foobar].
Martin Thoma,
zobacz także stackoverflow.com/questions/19078170/…
Graeme Stuart

Odpowiedzi:

148

To może być coś na początek:

import configparser

config = configparser.ConfigParser()
config.read('FILE.INI')
print(config['DEFAULT']['path'])     # -> "/path/name/"
config['DEFAULT']['path'] = '/var/shared/'    # update
config['DEFAULT']['default_message'] = 'Hey! help me!!'   # create

with open('FILE.INI', 'w') as configfile:    # save
    config.write(configfile)

Możesz znaleźć więcej w oficjalnej dokumentacji configparser .

Rik Poggi
źródło
4
Podaje w configparser.MissingSectionHeaderErrorprzypadku korzystania z dostarczonych plików przykładowych bez odpowiednich nagłówków sekcji.
Jaakko
81

Oto przykład pełnego odczytu, aktualizacji i zapisu.

Plik wejściowy, test.ini

[section_a]
string_val = hello
bool_val = false
int_val = 11
pi_val = 3.14

Kod roboczy.

try:
    from configparser import ConfigParser
except ImportError:
    from ConfigParser import ConfigParser  # ver. < 3.0

# instantiate
config = ConfigParser()

# parse existing file
config.read('test.ini')

# read values from a section
string_val = config.get('section_a', 'string_val')
bool_val = config.getboolean('section_a', 'bool_val')
int_val = config.getint('section_a', 'int_val')
float_val = config.getfloat('section_a', 'pi_val')

# update existing value
config.set('section_a', 'string_val', 'world')

# add a new section and some values
config.add_section('section_b')
config.set('section_b', 'meal_val', 'spam')
config.set('section_b', 'not_found_val', '404')

# save to a file
with open('test_update.ini', 'w') as configfile:
    config.write(configfile)

Plik wyjściowy, test_update.ini

[section_a]
string_val = world
bool_val = false
int_val = 11
pi_val = 3.14

[section_b]
meal_val = spam
not_found_val = 404

Oryginalny plik wejściowy pozostaje nietknięty.

Agostino
źródło
W moim systemie Python 3.7 wiersz „config.set ('section_b', 'not_found_val', 404)” musiał zostać zmieniony na „config.set ('section_b', 'not_found_val', str (404))”, ponieważ parametry dla „zestawu” muszą być łańcuchami. Doskonały przykład, dzięki!
Pan Ed
wygląda na to, że read metoda zwraca teraz listę odczytanych plików / plików, ale nie zawartość
YTerle
5

Standard ConfigParserzwykle wymaga dostępu przez config['section_name']['key'], co nie jest zabawne. Niewielka modyfikacja może zapewnić dostęp do atrybutów:

class AttrDict(dict):
    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__init__(*args, **kwargs)
        self.__dict__ = self

AttrDictjest klasą pochodną, dictktóra umożliwia dostęp zarówno przez klucze słownika, jak i dostęp do atrybutów: to znaczya.x is a['x']

Możemy wykorzystać tę klasę w ConfigParser:

config = configparser.ConfigParser(dict_type=AttrDict)
config.read('application.ini')

a teraz otrzymujemy application.ini:

[general]
key = value

tak jak

>>> config._sections.general.key
'value'
Robert Siemer
źródło
6
niezła sztuczka, ale użytkownicy tej metody powinni uważać, aby przy takim dostępie config._sections.general.key = "3"nie zmieniać wewnętrznej wartości opcji config i dlatego można jej używać tylko do odczytu. Jeśli po .read()poleceniu konfiguracja zostanie rozszerzona lub zmieniona (dodaj opcje, pary wartości dla niektórych sekcji, -> która dokonuje interpolacji, co może być bardzo ważne) to ta metoda dostępu nie powinna być używana! Również każdy dostęp, do config._sections["section"]["opt"]którego jest prywatny, omija interpolację i zwraca surowe wartości!
Gabriel
5

ConfigObj to dobra alternatywa dla ConfigParser, która oferuje znacznie większą elastyczność:

  • Zagnieżdżone sekcje (podsekcje) na dowolnym poziomie
  • Lista wartości
  • Wiele wartości linii
  • Interpolacja ciągów (podstawianie)
  • Zintegrowany z potężnym systemem walidacji, obejmującym automatyczne sprawdzanie typu / konwersję powtarzanych sekcji i zezwalanie na wartości domyślne
  • Podczas zapisywania plików konfiguracyjnych ConfigObj zachowuje wszystkie komentarze oraz kolejność elementów i sekcji
  • Wiele przydatnych metod i opcji pracy z plikami konfiguracyjnymi (np. Metoda „przeładowania”)
  • Pełna obsługa Unicode

Ma pewne wady:

  • Nie możesz ustawić separatora, musi to być =… ( żądanie ściągnięcia )
  • Nie możesz mieć pustych wartości, cóż, możesz, ale wyglądają na polubione: fuabr =zamiast po prostu fubarwyglądają dziwnie i źle.
Sardathrion - przeciwko nadużyciom SE
źródło
1
Sardathrion ma rację, ConfigObj to dobry sposób, jeśli chcesz zachować komentarze w pliku i kolejność sekcji, tak jak w oryginalnym pliku. ConfigParser po prostu wyczyści Twoje komentarze i w pewnym momencie zmieni kolejność.
Powstań
2

zawartość w moim pliku backup_settings.ini

[Settings]
year = 2020

kod Pythona do czytania

import configparser
config = configparser.ConfigParser()
config.read('backup_settings.ini') #path of your .ini file
year = config.get("Settings","year") 
print(year)

do pisania lub aktualizacji

from pathlib import Path
import configparser
myfile = Path('backup_settings.ini')  #Path of your .ini file
config.read(myfile)
config.set('Settings', 'year','2050') #Updating existing entry 
config.set('Settings', 'day','sunday') #Writing new entry
config.write(myfile.open("w"))

wynik

[Settings]
year = 2050
day = sunday
RK-Muscles God
źródło
To działa jak urok i jest czyste!
Rodrigo.A92