Параметры форматирования строки: плюсы и минусы

Это два очень популярных способа форматирования строки в Python. Один использует dict:

>>> 'I will be %(years)i on %(month)s %(day)i' % {'years': 21, 'month': 'January', 'day': 23}
'I will be 21 on January 23'

А другой с помощью простого tuple:

>>> 'I will be %i on %s %i' % (21, 'January', 23)
'I will be 21 on January 23'

Первый способ более удобочитаемый, а второй - быстрее. Я на самом деле использую их нечетко.

Каковы плюсы и минусы каждого? относительно производительности, читабельности, оптимизации кода (один из них преобразован в другой?) и всего, что вы считаете полезным поделиться.

3 ответа

Решение

Зачем format() является более гибким, чем % строковые операции

Я думаю, что вы должны придерживаться format() метод str потому что это предпочтительный способ форматирования строк и, вероятно, заменит операцию форматирования строки в будущем.

Кроме того, он имеет несколько действительно хороших функций, которые также могут сочетать форматирование на основе позиции с форматированием на основе ключевых слов:

>>> string = 'I will be {} years and {} months on {month} {day}'
>>> some_date = {'month': 'January', 'day': '1st'}
>>> diff = [3, 11] # years, months
>>> string.format(*diff, **some_date)
'I will be 3 years and 11 months on January 1st'

даже следующее будет работать:

>>> string = 'On {month} {day} it will be {1} months, {0} years'
>>> string.format(*diff, **some_date)
'On January 1st it will be 11 months, 3 years'

Есть и еще одна причина в пользу format(), Поскольку это метод, его можно передать как обратный вызов, как в следующем примере:

>>> data = [(1, 2), ('a', 'b'), (5, 'ABC')]
>>> formatter = 'First is "{0[0]}", then comes "{0[1]}"'.format
>>> for item in map(formatter, data):
    print item


First is "1", then comes "2"
First is "a", then comes "b"
First is "5", then comes "ABC"

Разве это не намного более гибко, чем операция форматирования строки?

Смотрите больше примеров на странице документации для сравнения % операции и .format() метод.

Сравнение на основе кортежей % форматирование строк с использованием словаря

Обычно есть три способа вызова % строковые операции (да, три, а не две):

base_string % values

и они отличаются по типу values (что является следствием того, что является содержанием base_string):

  • это может быть tuple затем они заменяются один за другим в порядке их появления в кортеже,

    >>> 'Three first values are: %f, %f and %f' % (3.14, 2.71, 1)
    'Three first values are: 3.140000, 2.710000 and 1.000000'
    
  • это может быть dict (словарь), то они заменяются на основе ключевых слов,

    >>> 'My name is %(name)s, I am %(age)s years old' % {'name':'John','age':98}
    'My name is John, I am 98 years old'
    
  • это может быть одно значение, если base_string содержит единственное место, где значение должно быть вставлено:

    >>> 'This is a string: %s' % 'abc'
    'This is a string: abc'
    

Между ними есть очевидные различия, и эти способы не могут быть объединены (в отличие от format() метод, который может сочетать некоторые функции, как указано выше).

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

>>> name = 'John'
>>> surname = 'Smith'
>>> age = 87
# some code goes here
>>> 'My name is %(surname)s, %(name)s %(surname)s. I am %(age)i.' % locals()
'My name is Smith, John Smith. I am 87.'

Просто для справки: конечно, вышесказанное можно легко заменить, используя format() распаковав словарь так:

>>> 'My name is {surname}, {name} {surname}. I am {age}.'.format(**locals())
'My name is Smith, John Smith. I am 87.'

Кто-нибудь еще имеет представление о том, что может быть функция, характерная для одного типа операции форматирования строки, но не для другого? Было бы довольно интересно услышать об этом.

Я не совсем отвечаю на ваш вопрос, но просто подумала, что было бы неплохо format в ваш микс.

Я лично предпочитаю синтаксис format как для:

'I will be {years} on {month} {day}'.format(years=19, month='January', day=23)

Если я хочу что-то компактное, я просто пишу:

'I will be {} on {} {}'.format(19, 'January', 23)

А также format хорошо играет с объектами:

class Birthday:
  def __init__(self, age, month, day):
    self.age = age
    self.month = month
    self.day = day

print 'I will be {b.age} on {b.month} {b.day}'.format(b = Birthday(19, 'January', 23))

Я не отвечаю на вопрос, а просто объясняю идею, которая возникла в моем TIScript.

Я ввел так называемые функции "stringizer": любая функция с именем, начинающимся с '$', является stringizer. Компилятор обрабатывает '$name(' и ')' как кавычки строкового литерала в сочетании с вызовом функции.

Пример такой:

$print(I will be {b.age} on {b.month} {b.day});

на самом деле компилируется в

$print("I will be ", b.age, " on ",b.month," ",b.day);

где четные аргументы всегда являются буквальными строками, а нечетные - выражениями. Таким образом, можно определить собственные строковые преобразователи, которые используют различное форматирование / обработку аргументов.

Например Element.$html(Hello <b>{who}</b>); будет применять HTML escape на выражениях. И это Element.$(option[value={12}]); сделаю выбор в стиле jQuery.

Довольно удобно и гибко.

Я не уверен, что возможно сделать что-то подобное в Python без изменения его компилятора. Рассматривайте просто как идею.

Другие вопросы по тегам