【问题标题】:load parameters from a file in Python在 Python 中从文件中加载参数
【发布时间】:2012-01-21 11:36:49
【问题描述】:

我正在编写一个 Python 类来对流程进行建模,并且我想从文件中初始化参数,例如 'input.dat'。输入文件的格式如下所示。

'input.dat'文件:

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

我写的代码如下。它有效,但显得多余且不灵活。有没有更好的方法来完成这项工作?比如循环做readline()然后匹配关键字?

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

【问题讨论】:

  • 我发现任何一天的初始格式化都比解析要好。在实践中已经改变了格式以更好地与 python 交互。如果你可以改变你的 input.dat,让它看起来更像是一个漂亮的 python 字典,你可以吸进整个 glob 并在它上面运行 eval()。所以在开头和结尾加上括号,在字符串周围加上引号,你会更开心!
  • @pyInTheSky:是的。不要eval() 配置文件。使用安全的东西,例如 JSONConfigParser
  • @Tim,基于 Python 的配置文件在某些​​情况下非常很有用,请参阅我的回答,例如:stackoverflow.com/a/8527168/68707
  • @Tim 当然 json 也可以。而且to nos :: json格式和python dict格式差不多,所以你可以导入json,做json.loads(file.read()),很快就能得到你想要的。

标签: python file serialization input


【解决方案1】:

您可以按如下方式遍历文件中的行:

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

等等。

【讨论】:

    【解决方案2】:

    也许这可能会给你你需要的东西:

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

    我也没有包含任何错误检查,但setattr 非常方便。

    【讨论】:

      【解决方案3】:

      尝试以下方法:

      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)
      

      证明它有效:

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

      【讨论】:

        【解决方案4】:

        类似这样的:

        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)
        

        【讨论】:

          【解决方案5】:
          • 如果您对其他可以保存参数的文件开放,我建议您使用YAML 文件。
          • python 库是 PyYAML This 是您可以轻松地将它与 Python 一起使用的方式
          • 为了更好的介绍,请看维基文章:http://en.wikipedia.org/wiki/YAML
          • 好处是您可以将参数值读取为列表、地图
          • 你会喜欢的!

          【讨论】:

          • 为什么不是 JSON 或 .INI,它们都内置在 Python 的 stdlib 中?或“导入”(见我的回答)。
          • @benhoyt,我想这更多是为了方便,我相信你的解决方案也可以:)
          【解决方案6】:

          Python 对象有一个内置的__dict__ 成员。你可以修改它,然后引用属性为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
          

          最后,我们打印出一些键。这是这些的输出。

          1.0
          20.0
          [0.0, 0.0]
          

          为了保持一致性,您可以在我的代码中删除标记为“可选”的行,并将所有对象都放在列表中——无论它们有多少元素。这将使使用它们变得相当容易,因为您永远不必担心obj.g[0] 返回错误。

          【讨论】:

            【解决方案7】:

            还有一个

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

            ;)

            【讨论】:

              【解决方案8】:

              假设参数来自安全的地方(由您或用户制作,而不是互联网),只需将参数文件设为 Python 文件,params.py

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

              那么在你的代码中你所需要的就是:

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

              这样做的好处有两个:1) 简单,2) 您可以在参数描述中使用 Python 的强大功能——在这里特别有用,例如:

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

              或者,您可以使用 Python 的内置 JSONConfigParser .INI parser 模块。

              【讨论】:

                【解决方案9】:

                正如其他人所提到的,在 Python 中,您可以动态创建对象属性“on the fly”。这意味着您可以执行以下操作来创建Params 对象,因为它们被读入。我试图让代码尽可能地由数据驱动,因此相对灵活。

                # 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
                

                输出:

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

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2023-03-06
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-06-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多