我想在API中提供自动字符串格式,以便:
my_api("path/to/{self.category}/{self.name}", ...)
可以替换为格式化字符串中调用的属性值。
如何从Python格式字符串中提取关键字参数:
"non-keyword {keyword1} {{escaped brackets}} {} {keyword2}" => 'keyword1', 'keyword2'
答案 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。