使用 Python ConfigParser,是否可以跨外部部分使用插值?我的大脑似乎告诉我我已经看到它可能在某个地方,但我在搜索时找不到它。
这个例子不起作用,但它是为了让我了解我正在尝试做的事情。
[section1]
root = /usr
[section2]
root = /usr/local
[section3]
dir1 = $(section1:root)/bin
dir2 = $(section2:root)/bin
请注意,我使用的是 Python 2.4。
使用 Python ConfigParser,是否可以跨外部部分使用插值?我的大脑似乎告诉我我已经看到它可能在某个地方,但我在搜索时找不到它。
这个例子不起作用,但它是为了让我了解我正在尝试做的事情。
[section1]
root = /usr
[section2]
root = /usr/local
[section3]
dir1 = $(section1:root)/bin
dir2 = $(section2:root)/bin
请注意,我使用的是 Python 2.4。
在 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,所以不,不能在python 2.4中进行部分插值。它是在python 3.2中引入的-请参阅第 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}
您确实可以访问特殊情况 [DEFAULT] 部分。即使对于旧版本的 Python,也可以通过其他部分的插值访问此处定义的值。
如果您坚持使用 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
注意事项:
我在我现在正在处理的项目中遇到了这个问题,并且我实现了一个快速扩展到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