Ответ 1
Вы можете использовать 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, если следующее имя должно рассматриваться как атрибут, и false, если это элемент, который нужно искать с помощью 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.