2011-12-15 10 views
9

Estoy escribiendo una clase de Python para modelar un proceso y quiero inicializar los parámetros desde un archivo, digamos 'input.dat'. El formato del archivo de entrada se ve así.cargar parámetros desde un archivo en Python

'input.dat' archivo:

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

El código que he escrito es el siguiente. Funciona, pero parece redundante e inflexible. ¿Hay una mejor manera de hacer el trabajo? Como un bucle para hacer readline() y luego coincide con la palabra clave?

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

me parece latidos de formato inicial de análisis sintáctico cualquier día. Y en la práctica han cambiado el formato para una mejor interfaz con Python. Si puede cambiar su input.dat, para parecerse más a un diccionario python bastante impreso, puede absorber todo el glob y ejecutar eval() en él. así que agrega corchetes al principio y al final, algunas comillas alrededor de las cuerdas, ¡y serás mucho más feliz! – pyInTheSky

+1

@pyInTheSky: Yech. No 'eval()' un archivo de configuración. Use algo seguro, como 'JSON' o' ConfigParser'. –

+0

archivos de configuración basada en Python @Tim, son * muy * útil en ciertos casos, véase mi respuesta, por ejemplo: http://stackoverflow.com/a/8527168/68707 –

Respuesta

9
  • Si están abiertos a algún otro tipo de archivo donde puede guardar sus parámetros, le sugiero que useArchivo.
  • El lib pitón es PyYAMLThis es cómo se puede utilizar fácilmente con Python
  • Para una mejor introducción, mira el artículo de wiki: http://en.wikipedia.org/wiki/YAML
  • La ventaja es que se puede visualizar los parámetros como la lista, mapas
  • ¡Te encantaría!
+0

+1 por sugerir YAML - I segundo esto. – Chris

+0

¿Por qué no JSON o .INI, que están integrados en el paquete stdlib de Python? O "importar" (ver mi respuesta). –

+0

@benhoyt, supongo que se trata más de conveniencia, estoy seguro de que su solución también funciona :) – daydreamer

0

Puede bucle sobre las líneas en un archivo de la siguiente manera:

for line in FILE: 
    s = line.split 
    var = s[0] 
    if var == 'z0:': 
     self.z0 = [float(s1), float(s2)] 
    elif var == 'k:': 
     etc. 

y así sucesivamente.

0

Tal vez esto podría darle lo que necesita:

def load(self,filename='input.dat'): 
    with open(filename) as fh: 
     for line in fh: 
      s = line.split() 
      if len(s) == 2: 
       setattr(self,s[1],s[2]) 
      elif len(s) == 3: 
       setattr(self,s[1],s[2:]) 

Asimismo, no incluyó ninguna comprobación de errores, pero setattr es muy práctico.

+0

lo siento edición, presentado por accidente: P – krs1

1

intente lo siguiente:

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) 

La prueba de que funciona:

>>> 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} 
0

Algo como esto:

def load(self,filename="input.dat"): 

    # maps names to number of fields they need 
    # only necessary for variables with more than 1 field 
    argmap = dict(Z0=2) 

    # maps config file names to their attribute names on the object 
    # if name is the same both places, no need 
    namemap = dict(Z0="z0", Delta="D", t_end="T") 

    with open(filename) as FILE: 
     for line in FILE: 
      s = line.split() 
      var = s[0].rstrip(":") 
      try: 
       val = [float(x) for x in s[1:]] 
      except ValueError: 
       continue 
      if len(val) == varmap.get(var, 1): 
       if len(val) == 1: 
        val = val[0] 
       setattr(self, namemap.get(var, var), val) 
0

Los objetos Python tienen incorporado un miembro __dict__. Puede modificarlo y luego consultar las propiedades como obj.key.

class Data(object): 
    def __init__(self, path='infile.dat'): 
    with open(path, 'r') as fo: 
     for line in fo.readlines(): 
     if len(line) < 2: continue 

     parts = [s.strip(' :\n') for s in line.split(' ', 1)] 
     numbers = [float(s) for s in parts[1].split()] 

     # This is optional... do you want single values to be stored in lists? 
     if len(numbers) == 1: numbers = numbers[0] 
     self.__dict__[parts[0]] = numbers 
     # print parts -- debug 

obj = Data('infile.dat') 
print obj.g 
print obj.Delta 
print obj.Z0 

Al final de esto, imprimimos algunas de las teclas. Aquí está la salida de aquellos.

1.0 
20.0 
[0.0, 0.0] 

Por coherencia, se puede quitar la línea marcada "opcional" en mi código, y tienen todos los objetos en las listas - independientemente del número de elementos que tienen. Eso hará que usarlos sea un poco más fácil, porque nunca tendrá que preocuparse por obj.g[0] devolviendo un error.

0

Aquí hay otro

def splitstrip(s): 
    return s.split(':')[1].strip() 

with open('input.dat','r') as f: 
    a.z0 = [float(x) for x in splitstrip(f.readline()).split(' ')] 
    a.k, a.g, a.D, a.T = tuple([float(splitstrip(x)) for x in f.read().rstrip().split('\n')]) 

;)

12

Suponiendo que los parametros son procedentes de un lugar seguro (hecho por usted o los usuarios, no internet), sólo hacen los parámetros del archivo de un archivo de Python, params.py:

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

Luego, en su código único que necesita es:

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

La belleza de esto es doble: 1) la simplicidad, y 2) que se puede usar el poder de Python en sus descripciones de los parámetros - particularmente útil en este caso, por ejemplo:

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

alternativa, podría utilizar los módulos incorporados de Python JSON o ConfigParser .INI parser.

1

Como otros han mencionado, en Python puede crear dinámicamente los atributos de objeto "on the fly". Eso significa que puede hacer algo como lo siguiente para crear objetos Params cuando se leen. Intenté hacer que el código sea lo más manejable posible, por lo que es relativamente 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 

Salida:

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