プロセスをモデル化するために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 file、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)
これの美しさは2つあります:1)シンプルさ、2)パラメータの説明でPython)の力を使用できます-ここでは特に便利です。たとえば、次のようになります。
k = 0.1
Delta = 20
g = 3 * k + Delta
または、Pythonの組み込み [〜#〜] json [〜#〜] または ConfigParser .INIパーサー モジュールを使用することもできます。
次のことを試してください。
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}
他の人が言及したように、Pythonではオブジェクト属性を動的に作成できます " オンザフライ "。つまり、次のようなことを実行して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
次のように、ファイルの行をループできます。
for line in FILE:
s = line.split
var = s[0]
if var == 'z0:':
self.z0 = [float(s1), float(s2)]
Elif var == 'k:':
etc.
等々。
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]
がエラーを返すことを心配する必要がないため、これにより、それらの使用が非常に簡単になります。
これがもう1つです
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')])
;)
おそらくこれはあなたが必要なものをあなたに与えるかもしれません:
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 はとても便利です。
このようなもの:
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)