如何从Python格式字符串中提取关键字?

时间:2014-09-23 13:52:39

标签: python string string-formatting

我想在API中提供自动字符串格式,以便:

my_api("path/to/{self.category}/{self.name}", ...)

可以替换为格式化字符串中调用的属性值。


如何从Python格式字符串中提取关键字参数:

"non-keyword {keyword1} {{escaped brackets}} {} {keyword2}" => 'keyword1', 'keyword2'

4 个答案:

答案 0 :(得分:41)

您可以使用string.Formatter() class使用Formatter.parse() method解析字符串中的字段:

from string import Formatter

fieldnames = [fname for _, fname, _, _ in Formatter().parse(yourstring) if fname]

演示:

>>> from string import Formatter
>>> yourstring = "path/to/{self.category}/{self.name}"
>>> [fname for _, fname, _, _ in Formatter().parse(yourstring) if fname]
['self.category', 'self.name']
>>> yourstring = "non-keyword {keyword1} {{escaped brackets}} {} {keyword2}"
>>> [fname for _, fname, _, _ in Formatter().parse(yourstring) if fname]
['keyword1', 'keyword2']

您可以进一步解析这些字段名称;为此,您可以使用str._formatter_field_name_split()方法(Python 2)/ _string.formatter_field_name_split()函数(Python 3)(此内部实现细节未以其他方式公开; Formatter.get_field()在内部使用它)。此函数返回名称的第一部分,在传递给str.format()的参数中查找的部分,以及该字段其余部分的生成器。

生成器产生(is_attribute, name)个元组;如果要将下一个名称视为属性,则is_attribute为true;如果是要使用obj[name]查找的项目,则为{:}

try:
    # Python 3
    from _string import formatter_field_name_split
except ImportError:
    formatter_field_name_split = str._formatter_field_name_split
from string import Formatter

field_references = {formatter_field_name_split(fname)[0]
 for _, fname, _, _ in Formatter().parse(yourstring) if fname}

演示:

>>> from string import Formatter
>>> from _string import formatter_field_name_split
>>> yourstring = "path/to/{self.category}/{self.name}"
>>> {formatter_field_name_split(fname)[0]
...  for _, fname, _, _ in Formatter().parse(yourstring) if fname}
{'self'}

考虑到此函数是Formatter()类的内部实现细节的一部分,可以在不事先通知的情况下从Python更改或删除,甚至可能在其他Python实现中不可用。

答案 1 :(得分:3)

如果所有占位符都已命名,则可以使用特殊字典来拦截尝试访问哪些密钥并将其记录到数组中。

def format_keys(str_):
    class HelperDict(dict):
        def __init__(self):
            self._keys = []
        def __getitem__(self, key):
            self._keys.append(key)    
    d = HelperDict()
    str_.format_map(d)
    return d._keys

请注意,如果存在未命名的占位符,则.format()将引发IndexError(元组索引超出范围)。

答案 2 :(得分:1)

建立Martijn的答案,我使用的综合列表的一种更简单的格式是:

>>> yourstring = "path/to/{self.category}/{self.name}"
>>> [x[1] for x in yourstring._formatter_parser() if x[1]]
['self.category', 'self.name']

它在功能上完全相同,更容易消化。

答案 3 :(得分:0)

你可以"path/to/{self.category}/{self.name}".format(self=self)。因此,您可以使用__getattr__中的那些kwargs。