2016-06-14 82 views
-1

給定一個格式字符串字典, 我想要做級聯/遞歸字符串插值。在python中級聯字符串插值

FOLDERS = dict(home="/home/user", 
       workspace="{home}/workspace", 
       app_project="{workspace}/{app_name}", 
       app_name="my_app") 

我開始用這個實現:

def interpolate(attrs): 
    remain = [k for k, v in attrs.items() if "{" in v] 
    while remain: 
     for k in remain: 
      attrs[k] = attrs[k].format(**attrs) 
     remain = [k for k in remain if "{" in attrs[k]] 

interpolate()功能首先選擇的格式字符串。 然後,它替換字符串,直到沒有更多的格式字符串保留。

當我打電話用下面的Python字典這個功能,我得到:

>>> import pprint 
>>> pprint.pprint(FOLDERS) 
{'app_name': 'my_app', 
'app_project': '/home/user/workspace/my_app', 
'home': '/home/user', 
'workspace': '/home/user/workspace'} 

結果是確定的,但這種做法不檢測的參考週期。

例如,以下調用導致無限循環!

>>> interpolate({'home': '{home}'}) 

任何人都可以給我一個更好的實施嗎?

編輯:解

我認爲萊昂的解決方案是好的,簡單,塞爾Bellesta過的一個。

我將實現這樣的說法:

def interpolate(attrs): 
    remain = [k for k, v in attrs.items() if "{" in v] 
    while remain: 
     for k in remain: 
      attrs[k] = attrs[k].format(**attrs) 
      fmt = '{' + k + '}' 
      if fmt in attrs[k]: # check for reference cycles 
       raise ValueError("Reference cycle found for '{k}'!".format(k=k)) 
     remain = [k for k in remain if "{" in attrs[k]] 
+2

*「?誰能給我一個更好的實施」 * - 這不是什麼意思。你試圖解決的實際問題是什麼?你真的會得到任何參考週期的輸入嗎? – jonrsharpe

+0

*「任何人都可以給我一個更好的實現?」* - 它只需要爲給定的輸入產生完全相同的結果? –

+0

如果其實我正在尋找一個通用的解決方案。這些例子僅用於說明。是的,如果定義文件夾的用戶在 - 通常 - 配置文件中發生錯誤,我們可以有循環:''interpolate()''函數應該找到它。 –

回答

1

可以在很容易地檢查這樣的參考週期的循環。只需檢查密鑰是否在for循環中的匹配值中被引用:

def interpolate(attrs): 
    remain = [k for k, v in attrs.items() if "{" in v] 
    while remain: 
     for k in remain: 
      attrs[k] = attrs[k].format(**attrs) 
      if '{%s}' % k in attrs[k]: # check for reference cycles 
       raise ValueError("Input contains at least one reference cycle!") 
     remain = [k for k in remain if "{" in attrs[k]] 

現在,如果存在引用週期,則會引發錯誤。這將檢測任何長度的參考週期,因爲它會被替換,直到找到一個或所有替換完成。

0

如果你的唯一的問題是,爲了避免無限循環檢測循環引用,你可以爲一個插補返回其輸入就立即停止:

def interpolate(attrs): 
    remain = [k for k, v in attrs.items() if "{" in v] 
    while remain: 
     for k in remain: 
      attrs[k] = attrs[k].format(**attrs) 
     temp = [k for k in remain if "{" in attrs[k]] 
     if temp == remain: 
      # cyclic reference detected 
      ... 
     remain = temp