2016-06-14 60 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