2017-07-17 10 views
1

我試圖從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語句。我的問題是如何在這種情況下做到這一點,當變量動態創建?

+0

爲什麼不只是製作一個'params = {}'字典,然後用你想要的任何東西來填充它,並使用'global params'來訪問它的函數。 – TemporalWolf

+0

是的,我想過使用字典,但使用'eval'函數來提取由表達式定義的參數值將會變得更加複雜。 –

+0

你不必評估它們,這就是要點。從查看你的代碼,你會過度複雜化整個事情。 – TemporalWolf

回答

1

注意: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 '': 
      return True 
     return st[-1] not in '' 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 : %s\n" % 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 
+0

是的,這是我想要的。如果我聽起來固執,我很抱歉,我不知道'shlex'軟件包。非常感謝您的幫助。 –

+0

@SalatielGarcia'shlex'是用於命令行處理,但在這種情況下,我認爲它會適用於你。 – TemporalWolf

相關問題