我正在尝试从SPICE网表文件中提取数据,特别是定义的参数。以下是文件"netlist.sp"的内容(感兴趣的(:
.param freq = 860x powS = 0
+ pi = 3.141592
+ nper = 15 cap1 = 68p
+ cycles = 20
+ tper = '1/freq'
+ tstep = 'tper/nper'
+ tstop = 'cycles*tper'
仅供参考,+
符号表示继续上一行,param = 'equation'
计算表达式。
因此,我正在尝试在 Python 3.6 中为每个参数创建一个全局变量。这是我到目前为止得到的代码:
def isnumber(s):
try:
float(s)
return True
except ValueError:
return False
#This function is needed to convert the '68p' format to '68e-12'
def floatify(st):
if not isnumber(st[-1]):
vals = [ 't', 'g', 'x', 'meg', 'k', 'm', 'u', 'n', 'p', 'f', 'a']
prod = [1e12, 1e9, 1e6, 1e6, 1e3, 1e-3, 1e-6, 1e-9, 1e-12, 1e-15, 1e-18]
pos = vals.index(st[-1])
st = st[:-1]
num = float(st) * prod[pos]
else:
num = float(st)
return num
#This is the main function
def params (file):
fl = 0
strng = '00'
tnum = 0.0
with open(file) as dat:
for line in dat:
if line.startswith('*'):
pass
elif line.startswith('.param '):
fl = 1
spl = line.split()
a = [i for i,x in enumerate(spl) if x=='=']
for i in range(len(a)):
strng = spl[a[i]-1]
try:
tnum = floatify(spl[a[i]+1])
except ValueError:
tnum = eval(spl[a[i]+1])
globals()[strng] = tnum
elif (line.find('+')+1) and fl:
spl = line.split()
a = [i for i,x in enumerate(spl) if x=='=']
for i in range(len(a)):
strng = spl[a[i]-1]
try:
tnum = floatify(spl[a[i]+1])
except ValueError:
temp = spl[a[i]+1]
tnum = eval(temp)
globals()[strng] = tnum
elif (not (line.find('+')+1)) and fl:
break
params('netlist.sp')
#Testing the variables
print('params done')
print('freq = ', freq)
print('powS = ', powS)
print('pi = ', pi)
print('nper = ', nper)
print('cap1 = ', cap1)
print('cycles = ', cycles)
print('tper = ', tper)
print('tstep = ', tstep)
print('tstop = ', tstop)
# Testing the eval function:
print(eval('1/freq'))
print(eval('2*pi'))
globals()[strng] = tnum
语句从提取的字符串创建全局变量并分配相应的值。
输出为:
freq = 860000000.0
powS = 0.0
pi = 3.141592
nper = 15.0
cap1 = 6.8e-11
cycles = 20.0
tper = 1/freq
tstep = tper/nper
tstop = cycles*tper
1.1627906976744186e-09
6.283184
因此,我从eval
函数的测试中了解到,在params
函数内部创建的全局变量仅在函数本身之外才能理解。我知道要修改函数内的全局变量,您必须在函数内声明global var
语句。我的问题是在这种情况下动态创建变量时如何做到这一点?
注意:repl.it 可以清理很多,但它确实适用于示例数据。
如本 repl.it 所示,您可以使用字典轻松完成此操作。
def fill_param(token):
for key in params.keys():
token = token.replace(key, str(params[key]))
return token
是允许这样做的关键:它使用 str.replace 在eval
之前填写我们已经知道的任何内容的值:
params[key] = eval(fill_param(value))
process_params()
的开始也很有趣:
global params
tokens = shlex.split(line)[1:]
我们导入字典,然后使用shlex.split()
对字符串进行标记化,省略第一个标记(.param
或+
,具体取决于行(。shlex.split()
很好,因为它尊重报价。
完整代码(以防 repl.it 死亡(。请注意,它还有很多不足之处,因为我花在这个问题上。我把清理工作留给读者作为练习。
import shlex
with open("netlist.sp", "w") as f:
f.write("""cabbage
garbage
.param freq = 860x powS = 0
+ pi = 3.141592
+ nper = 15 cap1 = 68p
+ cycles = 20
+ tper = '1/freq'
+ tstep = 'tper/nper'
+ tstop = 'cycles*tper'
sweet american freedom""")
params = {}
def param_it(in_f):
def isnumber(s):
try:
float(s)
return True
except ValueError:
return False
def floatify(st):
if not isnumber(st):
vals = [ 't', 'g', 'x', 'meg', 'k', 'm', 'u', 'n', 'p', 'f', 'a']
prod = [1e12, 1e9, 1e6, 1e6, 1e3, 1e-3, 1e-6, 1e-9, 1e-12, 1e-15, 1e-18]
pos = vals.index(st[-1])
st = st[:-1]
num = float(st) * prod[pos]
else:
num = float(st)
return num
def number(st):
if isnumber(st) or len(st) == 1 and st in '0123456789':
return True
return st[-1] not in '0123456789' and isnumber(st[:-1])
def process_params(line):
global params
tokens = shlex.split(line)[1:]
assert len(tokens) % 3 == 0
for i in range(len(tokens)/3):
key = tokens[i*3]
value = tokens[i*3 + 2]
print "Processing key: %s value: %s... " % (key, value),
if number(value):
try:
value = float(value)
except ValueError:
value = floatify(value)
params[key] = value
else:
try:
params[key] = eval(fill_param(value))
except Exception as e: # eval can throw essentially any exception
print "Failed to parse value for k/v %s:%s" % (key, value)
raise
print "Converted value is : %sn" % params[key]
def fill_param(token):
for key in params.keys():
token = token.replace(key, str(params[key]))
return token
with open(in_f, "r") as f:
param = False
for line in f:
if line.startswith(".param "):
process_params(line)
param = True
elif param and line.startswith("+"):
process_params(line)
elif param:
break
param_it("netlist.sp")
print params