Как я могу удовлетворить различные сценарии форматирования строки с одним и тем же кодом? - PullRequest
3 голосов
/ 14 апреля 2019

У меня есть входной файл, который содержит строку текста заполнителя и связанных значений. Я действительно заранее не знаю, какие из них появятся, и мне было любопытно, есть ли один кодовый блок, который может удовлетворить все следующие комбинации строк-заполнителей и предоставленных значений.

По сути, я хочу это:

examples = [
    {"text": "There are {} bagels in a bakers dozen.", "values": 13},
    {"text": "My favorite bagels are {} and {}.", "values": ["cinnamon raisin", "maple"]},
    {"text": "I have not had a pop tart in 14 {}", "values": "years"}
]

for single_example in examples:
    print(single_example['text'].format(single_example['values']))

Однако format(single_example['values']) не работает для второго text. Вместо этого я могу сделать format(*single_example['values']), чтобы позволить второму примеру работать, но первый сломался бы с ошибкой IndexError: tuple index out of range, а третий - нарезкой строки.

Я думаю, мне нужно все составить в виде списка, чтобы format(*single_example['values']) работал по всем направлениям, но я застрял, находя подход, который работает для вышеупомянутых случаев.

Это работает для меня, но я чувствую, что может быть более обтекаемый подход.

for single_example in examples:
    if isinstance(single_example['values'], list):
        values = single_example['values']
    else:
        lst = []
        lst.append(str(single_example['values']))
        values = lst
    print(single_example['text'].format(*values))

Ответы [ 6 ]

2 голосов
/ 14 апреля 2019

Почему бы не использовать try except предложение:

for single_example in examples:
    try:
        print(single_example['text'].format(single_example['values']))
    except:
        print(single_example['text'].format(*single_example['values']))

Выход:

There are 13 bagels in a bakers dozen.
My favorite bagels are cinnamon raisin and maple.
I have not had a pop tart in 14 years
2 голосов
/ 14 апреля 2019

Вы можете сохранить все значения в списке:

examples = [
    {"text": "There are {} bagels in a bakers dozen.", "values": [13]},
    {"text": "My favorite bagels are {} and {}.", "values": ["cinnamon raisin", "maple"]},
    {"text": "I have not had a pop tart in 14 {}", "values": ["years"]}
]

for single_example in examples:
    print(single_example['text'].format(*single_example['values']))

Выход:

There are 13 bagels in a bakers dozen.
My favorite bagels are cinnamon raisin and maple.
I have not had a pop tart in 14 years

EDIT

Если у вас нет контроля над входными данными, вы можете преобразовать значения по мере необходимости:

examples = [
    {"text": "There are {} bagels in a bakers dozen.", "values": 13},
    {"text": "My favorite bagels are {} and {}.", "values": ["cinnamon raisin", "maple"]},
    {"text": "I have not had a pop tart in 14 {}", "values": "years"}
]

for single_example in examples:
    values = single_example['values'] if isinstance(single_example['values'], list) else [single_example['values']]
    print(single_example['text'].format(*values))
1 голос
/ 14 апреля 2019

Упрощение существующего кода:

for single_example in examples:
    if isinstance(single_example['values'], list):
        values = single_example['values']
    else:
        values = [single_example['values']]
    print(single_example['text'].format(*values))

Вывод:

There are 13 bagels in a bakers dozen.
My favorite bagels are cinnamon raisin and maple.
I have not had a pop tart in 14 years
1 голос
/ 14 апреля 2019

Вы можете иметь if-else внутри format, если ваш вход не может быть изменен:

examples = [
    {"text": "There are {} bagels in a bakers dozen.", "values": 13},
    {"text": "My favorite bagels are {} and {}.", "values": ["cinnamon raisin", "maple"]},
    {"text": "I have not had a pop tart in 14 {}", "values": "years"}
]

for single_example in examples:
    print(single_example['text'].format(*single_example['values'] if isinstance(single_example['values'], (list, tuple)) else [single_example['values']]))

# There are 13 bagels in a bakers dozen.
# My favorite bagels are cinnamon raisin and maple.
# I have not had a pop tart in 14 years
0 голосов
/ 14 апреля 2019

Не сильно отличается от других ответов, но я бы использовал два списка вместо одного словаря и сжал бы оба списка. Затем для каждого индекса списка примеров распакуйте их соответствующим образом.

def format_custom_text(string, values):
    # Unpack the values
    return string.format(*values)


values = [
    13,
    ['cinnamon raisin', 'maple'],
    'years'
]

# You don't need a dictionary to store the examples
examples = [
    "There are {} bagels in a bakers dozen.",
    "My favorite bagels are {} and {}.",
    "I have not had a pop tart in 14 {}."
]

for single_example in zip(examples, values):
    # Convert each value inside the values list into a list
    placeholder_values = []
    if not type(single_example[1]) == list:
        placeholder_values.append(single_example[1])
    else:
        placeholder_values = single_example[1]
0 голосов
/ 14 апреля 2019

Я думаю, что следующая функция - лучший способ проверить, является ли значение «скалярным», и перейти на него. Numpy немного велик для импорта только для этого, но он работает.

def as_iterable(x): 
    from numpy import isscalar 
    if isscalar(x):  # Includes numbers and strings
        yield x 
    else:            # Lists, tuples, etc
        yield from x

Теперь вы можете сделать это:

examples = [ 
    {"text": "There are {} bagels in a bakers dozen.", "values": 13}, 
    {"text": "My favorite bagels are {} and {}.", "values": ["cinnamon raisin", "maple"]},
    {"text": "I have not had a pop tart in 14 {}", "values": "years"} 
] 

for single_example in examples: 
    print(single_example['text'].format(*as_iterable(single_example['values']))) 
...