【问题标题】:Python ConfigParser interpolation from foreign section来自外部部分的 Python ConfigParser 插值
【发布时间】:2011-09-30 01:35:22
【问题描述】:

使用 Python ConfigParser,是否可以跨外部部分使用插值?我的大脑似乎告诉我,我已经看到它可能在某个地方,但我在搜索时找不到它。

这个例子不起作用,但它是为了让我知道我正在尝试做什么。

[section1]
root = /usr

[section2]
root = /usr/local

[section3]
dir1 = $(section1:root)/bin
dir2 = $(section2:root)/bin

请注意,我使用的是 Python 2.4。

【问题讨论】:

    标签: python python-2.7 python-2.x configparser python-2.4


    【解决方案1】:

    在 python 3.2 及更高版本中这是完全有效的:

    [Common]
    home_dir: /Users
    library_dir: /Library
    system_dir: /System
    macports_dir: /opt/local
    
    [Frameworks]
    Python: 3.2
    path: ${Common:system_dir}/Library/Frameworks/
    
    [Arthur]
    nickname: Two Sheds
    last_name: Jackson
    my_dir: ${Common:home_dir}/twosheds
    my_pictures: ${my_dir}/Pictures
    python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python}
    

    编辑:

    我刚刚看到你使用的是python 2.4,所以no,在python 2.4中不能进行分段插值时间>。它是在 python 3.2 中引入的 - See section 13.2.5 - ConfigParser Interpolation of values

    班级configparser.ExtendedInterpolation

    另一种处理程序 用于实现更高级语法的插值,用于 zc.buildout 中的实例。扩展插值正在使用 ${section:option} 表示来自外部部分的值。 插值可以跨越多个级别。为方便起见,如果 section:省略部分,插值默认为当前 部分(可能还有特殊部分的默认值)。 例如,上面指定的配置与基本 插值,使用扩展插值看起来像这样:

       [Paths]
       home_dir: /Users
       my_dir: ${home_dir}/lumberjack
       my_pictures: ${my_dir}/Pictures
    

    也可以从其他部分获取值:

       [Common]
       home_dir: /Users
       library_dir: /Library
       system_dir: /System
       macports_dir: /opt/local
    
       [Frameworks]
       Python: 3.2
       path: ${Common:system_dir}/Library/Frameworks/
    
       [Arthur]
       nickname: Two Sheds
       last_name: Jackson
       my_dir: ${Common:home_dir}/twosheds
       my_pictures: ${my_dir}/Pictures
       python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python}
    

    【讨论】:

    • 看起来你的语法和头脑有点不同。您使用的是 ${section:name} 而不是我使用的 %(section:name)s。我试过了,但没有用。
    • 啊,抱歉,我没有意识到您指的是跨节的字符串插值。我相信 3.2 也有,让我仔细检查一下。
    • 我刚刚在 Python 3.2 文档 (configparser.ExtendedInterpolation) 中找到了您所拥有的内容,但它没有列出添加的时间。当我查看 Python 2.4 文档(我正在使用的)时,没有显示。我猜它是在 2.4 和 3.2 之间添加的。
    • 是的,我检查了 ConfigParser 从 2.4 到 3.2 的每个版本文档,第一个具有 ExtendedInterpolation 类的文档是 3.2。
    • 他们可能应该在文档中添加“Python 3.2 中的新功能”。它派上用场了。
    【解决方案2】:

    您确实可以访问特殊情况的 [DEFAULT] 部分。即使对于旧版本的 Python,也可以通过其他部分的插值访问此处定义的值。

    【讨论】:

    • 您能详细说明一下吗?请举个例子。甚至是来源参考。
    • Hamed,看看这里。 docs.python.org/2/library/configparser.html。基本上(并且您可以下载并阅读代码)如果您尝试从特定 [section] 读取“name”的“value”,但该 [section] 中没有“name=value”,那么配置解析器在 [DEFAULT] 部分中查找“name=value”,如果存在则返回。
    【解决方案3】:

    如果您使用 python 2.7 并且需要进行横截面插值,则使用正则表达式手动执行此操作很容易。

    代码如下:

    INTERPOLATION_RE = re.compile(r"\$\{(?:(?P<section>[^:]+):)?(?P<key>[^}]+)\}")
    
    def load_something_from_cp(cp, section="section"):
        result = []
        def interpolate_func(match):
            d = match.groupdict()
            section = d.get('section', section)
            key = d.get('key')
            return cp.get(section, key)
        for k, v in cp.items(section):
            v = re.sub(INTERPOLATION_RE, interpolate_func, v)
            result.append(
                (v, k)
            )
        return result
    

    注意事项:

    • 插值中没有递归
    • 在解析多个部分时,您需要以某种方式猜测当前部分。

    【讨论】:

      【解决方案4】:

      我在我现在正在处理的项目中遇到了这个问题,我实现了对 ConfigParser.SafeConfigParser 类的快速扩展,其中我覆盖了 get() 函数。我想有些人可能会觉得它很有用。

      import re
      import ConfigParser
      
      class ExtParser(ConfigParser.SafeConfigParser):
           #implementing extended interpolation
           def __init__(self, *args, **kwargs):
               self.cur_depth = 0 
               ConfigParser.SafeConfigParser.__init__(self, *args, **kwargs)
      
      
           def get(self, section, option, raw=False, vars=None):
               r_opt = ConfigParser.SafeConfigParser.get(self, section, option, raw=True, vars=vars)
               if raw:
                   return r_opt
      
               ret = r_opt
               re_oldintp = r'%\((\w*)\)s'
               re_newintp = r'\$\{(\w*):(\w*)\}'
      
               m_new = re.findall(re_newintp, r_opt)
               if m_new:
                   for f_section, f_option in m_new:
                       self.cur_depth = self.cur_depth + 1 
                       if self.cur_depth < ConfigParser.MAX_INTERPOLATION_DEPTH:
                           sub = self.get(f_section, f_option, vars=vars)
                           ret = ret.replace('${{{0}:{1}}}'.format(f_section, f_option), sub)
                       else:
                           raise ConfigParser.InterpolationDepthError, (option, section, r_opt)
      
      
      
               m_old = re.findall(re_oldintp, r_opt)
               if m_old:
                   for l_option in m_old:
                       self.cur_depth = self.cur_depth + 1 
                       if self.cur_depth < ConfigParser.MAX_INTERPOLATION_DEPTH:
                           sub = self.get(section, l_option, vars=vars)
                           ret = ret.replace('%({0})s'.format(l_option), sub)
                       else:
                           raise ConfigParser.InterpolationDepthError, (option, section, r_opt)
      
               self.cur_depth = self.cur_depth - 1 
               return ret 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多