load parameters from a file in Python

48,942

Solution 1

  • If you are open to some other kind of file where you can keep your parameters, I would suggest you to use YAML file.
  • The python lib is PyYAML This is how you can easily use it with Python
  • For better introduction, look at the wiki article : http://en.wikipedia.org/wiki/YAML
  • The benefit is you can read the parameter values as list, maps
  • You would love it!

Solution 2

Assuming the params are coming from a safe place (made by you or users, not the internet), just make the parameters file a Python file, params.py:

Z0 = (0, 0)
k = 0.1
g = 1
Delta = 20
t_end = 300

Then in your code all you need is:

import params
fancy_calculation(10, k=params.k, delta=params.Delta)

The beauty of this is two-fold: 1) simplicity, and 2) you can use the power of Python in your parameter descriptions -- particularly useful here, for example:

k = 0.1
Delta = 20
g = 3 * k + Delta

Alternatively, you could use Python's built-in JSON or ConfigParser .INI parser modules.

Solution 3

As others have mentioned, in Python you can create object attributes dynamically "on the fly". That means you could do something like the following to create Params objects as they're read-in. I've tried to make the code as data-driven as possible, so relatively flexible.

# maps label to attribute name and types
label_attr_map = {
       "Z0:": ["z0", float, float],
        "k:": [ "k", float],
        "g:": [ "g", float],
    "Delta:": [ "D", float],
    "t_end:": [ "T", float]
}

class Params(object):
    def __init__(self, input_file_name):
        with open(input_file_name, 'r') as input_file:
            for line in input_file:
                row = line.split()
                label = row[0]
                data = row[1:]  # rest of row is data list

                attr = label_attr_map[label][0]
                datatypes = label_attr_map[label][1:]

                values = [(datatypes[i](data[i])) for i in range(len(data))]
                self.__dict__[attr] = values if len(values) > 1 else values[0]


params = Params('input.dat')
print 'params.z0:', params.z0
print 'params.k:', params.k
print 'params.g:', params.g
print 'params.D:', params.D
print 'params.T:', params.T

Output:

params.z0: [0.0, 0.0]
params.k: 0.1
params.g: 1.0
params.D: 20.0
params.T: 300.0

Solution 4

Try the following:

def load(self, filename="input.dat"):
    d = {"Z0": "z0", "k": "k", "g": "g", "Delta": "D", "t_end": "T"}
    FILE = open(filename)
    for line in FILE:
        name, value = line.split(":")
        value = value.strip()
        if " " in value:
            value = map(float, value.split())
        else:
            value = float(value)
        setattr(self, d[name], value)

Proof that it works:

>>> class A(object): pass
...
>>> a = A()
>>> load(a)
>>> a.__dict__
{'k': 0.10000000000000001, 'z0': [0.0, 0.0], 'D': 20.0, 'g': 1.0, 'T': 300.0}
Share:
48,942
nos
Author by

nos

Hello fellow programmers! I maintain open source software and blog about science and technology in my spare time. Main projects: gita: A command-line tool to manage multiple git repos (1000+ ⭐) blog where I write about math, physics, coding, and hobbies youtube channel: productivity hacks and coding tips

Updated on August 06, 2020

Comments

  • nos
    nos almost 4 years

    I am writing a Python class to model a process and I want to initialized the parameters from a file, say 'input.dat'. The format of the input file looks like this.

    'input.dat' file:

    Z0: 0 0
    k: 0.1
    g: 1
    Delta: 20
    t_end: 300
    

    The code I wrote is the following. It works but appears redundant and inflexible. Is there a better way to do the job? Such as a loop to do readline() and then match the keyword?

    def load(self,filename="input.dat"):
        FILE = open(filename)
        s = FILE.readline().split()
        if len(s) is 3:
            self.z0 = [float(s[1]),float(s[2])] # initial state
        s = FILE.readline().split()
        if len(s) is 2:
            self.k = float(s[1])    # kappa
        s = FILE.readline().split()
        if len(s) is 2:
            self.g = float(s[1])
        s = FILE.readline().split()
        if len(s) is 2:
            self.D = float(s[1])    #  Delta
        s = FILE.readline().split()
        if len(s) is 2:
            self.T = float(s[1])    # end time
    
  • Ben Hoyt
    Ben Hoyt over 12 years
    Why not JSON or .INI, which are both built into Python's stdlib? Or "import" (see my answer).
  • daydreamer
    daydreamer over 12 years
    @benhoyt, I guess its more about convenience, I am sure your solution works too :)