A config file keeps settings such as a port number or a debug switch outside your code, so you can change them without editing the program. This reader starts from default values and lets the file replace only the settings it lists.
The program
import json DEFAULTS = {"host": "localhost", "port": 8000, "debug": False, "log_level": "INFO"} # create a sample config file so this example has something to read with open("config.json", "w", encoding="utf-8") as f: json.dump({"port": 8080, "debug": True}, f) def load_config(path, defaults): config = dict(defaults) try: with open(path, encoding="utf-8") as f: config.update(json.load(f)) except FileNotFoundError: print(f"{path} not found, using the defaults") return config config = load_config("config.json", DEFAULTS) for key, value in config.items(): print(f"{key} = {value!r}") print(load_config("missing.json", DEFAULTS)["port"])
host = 'localhost' port = 8080 debug = True log_level = 'INFO' missing.json not found, using the defaults 8000
How it works
dict(defaults)makes a copy, so loading a file never changesDEFAULTSitself.config.update(...)copies every setting from the file over the copy. Settings the file does not mention, herehostandlog_level, keep their default values.- JSON keeps types:
8080comes back as an int andtrueas the Python valueTrue, so you do not need to convert them. - A missing file raises
FileNotFoundError. The program catches it and uses the defaults. A file with broken JSON raisesjson.JSONDecodeError, which is not caught, because a broken config file is something you want to see and fix.
Another way: an INI file
INI files are plain text with [sections] and key = value lines. The standard library reads them with configparser:
import configparser with open("settings.ini", "w", encoding="utf-8") as f: f.write("[server]\nhost = example.com\nport = 8080\n\n[app]\ndebug = yes\n") parser = configparser.ConfigParser() parser.read("settings.ini", encoding="utf-8") host = parser.get("server", "host") port = parser.getint("server", "port") debug = parser.getboolean("app", "debug") timeout = parser.getint("server", "timeout", fallback=30) print(host, port, debug, timeout)
example.com 8080 True 30
INI values are always read as text, so use getint() and getboolean() to convert them. getboolean() accepts yes/no, on/off, true/false and 1/0. fallback=30 is the value to use when the setting is missing.