我想在 API 中提供自动字符串格式设置,以便:
my_api("path/to/{self.category}/{self.name}", ...)
可以替换为格式化字符串中调用的属性值。
如何从 Python 格式字符串中提取关键字参数:
"non-keyword {keyword1} {{escaped brackets}} {} {keyword2}" => 'keyword1', 'keyword2'
string.Formatter()
类 来解析字符串中的字段,并使用 Formatter.parse()
方法:
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]
查找的项目,则为 false:
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 实现中不可用。
更新: _formatter_parser() 是一个私有方法,因此对于 python >= 3.8 甚至更早的版本不再可用
根据 Martijn 的答案,我使用的综合列表的更简单格式是:
>>> yourstring = "path/to/{self.category}/{self.name}"
>>> [x[1] for x in yourstring._formatter_parser() if x[1]]
['self.category', 'self.name']
它的功能完全相同,只是更容易消化。
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。
"path/to/{self.category}/{self.name}".format(self=self)
。因此,您可以在
__getattr__
中使用那些 kwargs。