Параметры форматирования строки: плюсы и минусы - PullRequest
22 голосов
/ 06 декабря 2011

Это два очень популярных способа форматирования строки в 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 ]

21 голосов
/ 06 декабря 2011

Почему 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.'

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

20 голосов
/ 06 декабря 2011

Я не совсем отвечаю на ваш вопрос, но просто подумал, что было бы неплохо добавить 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))
0 голосов
/ 06 декабря 2011

Я не отвечаю на вопрос, а просто объясняю идею, которую я придумал в моем 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 к выражениям.И этот Element.$(option[value={12}]); сделает выбор в стиле jQuery.

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

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

...