Форматирование строки Python:% против .format

Python 2. 6 представил метод str.format() с немного отличающимся синтаксисом от существующего оператора %. Что лучше и для каких ситуаций?

  1. Следующее использует каждый метод и имеет тот же результат, так в чем же разница?

    #!/usr/bin/python
    sub1 = "python string!"
    sub2 = "an arg"
    
    a = "i am a %s" % sub1
    b = "i am a {0}".format(sub1)
    
    c = "with %(kwarg)s!" % {'kwarg':sub2}
    d = "with {kwarg}!".format(kwarg=sub2)
    
    print a    # "i am a python string!"
    print b    # "i am a python string!"
    print c    # "with an arg!"
    print d    # "with an arg!"
    
  2. Кроме того, когда происходит форматирование строки в Python? Например, если мой уровень ведения журнала установлен на ВЫСОКИЙ, получу ли я удар для выполнения следующей операции %? И если так, есть ли способ избежать этого?

    log.debug("some debug info: %s" % some_info)
    
вопрос задан 22.02.2011
NorthIsUp
7273 репутация

15 ответов


  • 855 рейтинг

    Чтобы ответить на ваш первый вопрос. , , .format просто кажется более сложным во многих отношениях. Раздражает % также то, как он может принимать переменную или кортеж. Можно подумать, что всегда будет работать следующее:

    "hi there %s" % name
    

    пока, если name окажется (1, 2, 3), он бросит TypeError. Чтобы гарантировать, что он всегда печатает, вам нужно сделать

    "hi there %s" % (name,)   # supply the single argument as a single-item tuple
    

    , который просто безобразен. .format не имеет этих проблем. Также во втором примере, который вы привели, пример .format выглядит намного чище.

    Почему бы вам не использовать его?

    • не зная об этом (я, прежде чем читать это)
    • должен быть совместим с Python 2. 5

    Чтобы ответить на ваш второй вопрос, форматирование строки происходит одновременно с любой другой операцией - когда вычисляется выражение форматирования строки. И Python, не будучи ленивым языком, вычисляет выражения перед вызовом функций, поэтому в вашем примере log.debug выражение "some debug info: %s"%some_info сначала оценит в, e. г. "some debug info: roflcopters are active", то эта строка будет передана log.debug().

    ответ дан Claudiu, с репутацией 122117, 22.02.2011
  • 282 рейтинг

    То, что оператор по модулю (%) не может сделать, afaik:

    tu = (12,45,22222,103,6)
    print '{0} {2} {1} {2} {3} {2} {4} {2}'.format(*tu)
    

    результат

    12 22222 45 22222 103 22222 6 22222
    

    Очень полезно.

    Другой момент: format(), будучи функцией, может использоваться как аргумент в других функциях:

    li = [12,45,78,784,2,69,1254,4785,984]
    print map('the number is {}'.format,li)   
    
    print
    
    from datetime import datetime,timedelta
    
    once_upon_a_time = datetime(2010, 7, 1, 12, 0, 0)
    delta = timedelta(days=13, hours=8,  minutes=20)
    
    gen =(once_upon_a_time +x*delta for x in xrange(20))
    
    print '\n'.join(map('{:%Y-%m-%d %H:%M:%S}'.format, gen))
    

    Результаты в:

    ['the number is 12', 'the number is 45', 'the number is 78', 'the number is 784', 'the number is 2', 'the number is 69', 'the number is 1254', 'the number is 4785', 'the number is 984']
    
    2010-07-01 12:00:00
    2010-07-14 20:20:00
    2010-07-28 04:40:00
    2010-08-10 13:00:00
    2010-08-23 21:20:00
    2010-09-06 05:40:00
    2010-09-19 14:00:00
    2010-10-02 22:20:00
    2010-10-16 06:40:00
    2010-10-29 15:00:00
    2010-11-11 23:20:00
    2010-11-25 07:40:00
    2010-12-08 16:00:00
    2010-12-22 00:20:00
    2011-01-04 08:40:00
    2011-01-17 17:00:00
    2011-01-31 01:20:00
    2011-02-13 09:40:00
    2011-02-26 18:00:00
    2011-03-12 02:20:00
    
    ответ дан eyquem, с репутацией 19220, 13.06.2011
  • 126 рейтинг

    Предполагая, что вы используете модуль Python logging, вы можете передавать аргументы форматирования строки в качестве аргументов методу .debug(), а не выполнять форматирование самостоятельно:

    log.debug("some debug info: %s", some_info)
    

    , который избегает форматирования, если регистратор что-то не регистрирует.

    ответ дан geoffspear, с репутацией 63730, 22.02.2011
  • 90 рейтинг

    Начиная с Python 3. 6 (2016) вы можете использовать f-строк для замены переменных:

    >>> origin = "London"
    >>> destination = "Paris"
    >>> f"from {origin} to {destination}"
    'from London to Paris'
    

    Обратите внимание на префикс f". Если вы попробуете это в Python 3. 5 или раньше, вы получите SyntaxError.

    См. https: // docs. питон. орг / 3. 6 / ссылка / lexical_analysis. html # f-strings

    ответ дан Colonel Panic, с репутацией 77755, 15.04.2016
  • 54 рейтинг

    PEP 3101 предлагает заменить оператор % новым расширенным форматированием строк в Python 3, где оно будет использоваться по умолчанию.

    ответ дан BrainStorm, с репутацией 1544, 1.08.2011
  • 51 рейтинг

    Но, пожалуйста, будьте осторожны, только сейчас я обнаружил одну проблему при попытке заменить все % на .format в существующем коде: '{}'.format(unicode_string) попытается кодировать unicode_string и, вероятно, завершится ошибкой.

    Просто посмотрите на этот интерактивный журнал сеансов Python:

    Python 2.7.2 (default, Aug 27 2012, 19:52:55) 
    [GCC 4.1.2 20080704 (Red Hat 4.1.2-48)] on linux2
    ; s='й'
    ; u=u'й'
    ; s
    '\xd0\xb9'
    ; u
    u'\u0439'
    

    s - это просто строка (называемая «байтовый массив» в Python3), а u - это строка Unicode (называемая «строка» в Python3):

    ; '%s' % s
    '\xd0\xb9'
    ; '%s' % u
    u'\u0439'
    

    Когда вы передаете объект Unicode в качестве параметра для оператора %, он будет генерировать строку Unicode, даже если исходная строка не была Unicode:

    ; '{}'.format(s)
    '\xd0\xb9'
    ; '{}'.format(u)
    Traceback (most recent call last):
      File "", line 1, in 
    UnicodeEncodeError: 'latin-1' codec can't encode character u'\u0439' in position 0: ordinal not in range(256)
    

    , но функция .format вызовет «UnicodeEncodeError»:

    ; u'{}'.format(s)
    u'\xd0\xb9'
    ; u'{}'.format(u)
    u'\u0439'
    

    , и он будет работать с аргументом Unicode нормально, только если исходная строка была Unicode.

    ; '{}'.format(u'i')
    'i'
    

    или если строка аргумента может быть преобразована в строку (так называемый «байтовый массив»)

    ответ дан rslnx, с репутацией 898, 3.09.2012
  • 33 рейтинг

    Еще одно преимущество .format (которого я не вижу в ответах): он может принимать свойства объекта.

    In [12]: class A(object):
       ....:     def __init__(self, x, y):
       ....:         self.x = x
       ....:         self.y = y
       ....:         
    
    In [13]: a = A(2,3)
    
    In [14]: 'x is {0.x}, y is {0.y}'.format(a)
    Out[14]: 'x is 2, y is 3'
    

    Или, в качестве ключевого аргумента:

    In [15]: 'x is {a.x}, y is {a.y}'.format(a=a)
    Out[15]: 'x is 2, y is 3'
    

    Это невозможно с %, насколько я могу судить.

    ответ дан matiasg, с репутацией 1288, 4.12.2014
  • 27 рейтинг

    Как я обнаружил сегодня, старый способ форматирования строк с помощью % не поддерживает «из коробки» модуль Decimal, модуль Python для десятичной фиксированной запятой и арифметики с плавающей запятой.

    Пример (с использованием Python 3. 3. 5):

    #!/usr/bin/env python3
    
    from decimal import *
    
    getcontext().prec = 50
    d = Decimal('3.12375239e-24') # no magic number, I rather produced it by banging my head on my keyboard
    
    print('%.50f' % d)
    print('{0:.50f}'.format(d))
    

    Выход:

    0. 00000000000000000000000312375239000000009907464850 0. 00000000000000000000000312375239000000000000000000

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

    ответ дан balu, с репутацией 1492, 13.05.2014
  • 22 рейтинг

    % дает лучшую производительность, чем format из моего теста.

    Тестовый код:

    Python 2. 7. 2:

    import timeit
    print 'format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')")
    print '%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')")
    

    Результат:

    > format: 0.470329046249
    > %: 0.357107877731
    

    Python 3. 5. 2

    import timeit
    print('format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')"))
    print('%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')"))
    

    Результат

    > format: 0.5864730989560485
    > %: 0.013593495357781649
    

    Это выглядит в Python2, разница невелика, тогда как в Python3 % намного быстрее, чем format.

    Спасибо @Chris Cogdon за пример кода.

    ответ дан lcltj, с репутацией 1055, 13.06.2011
  • 14 рейтинг

    В качестве примечания, вам не нужно снижать производительность, чтобы использовать новый стиль форматирования с ведением журнала. Вы можете передать любой объект logging.debug, logging.info и т. Д. который реализует магический метод __str__. Когда модуль протоколирования решил, что он должен выдать ваш объект сообщения (каким бы он ни был), он вызывает str(message_object), прежде чем сделать это. Таким образом, вы могли бы сделать что-то вроде этого:

    import logging
    
    
    class NewStyleLogMessage(object):
        def __init__(self, message, *args, **kwargs):
            self.message = message
            self.args = args
            self.kwargs = kwargs
    
        def __str__(self):
            args = (i() if callable(i) else i for i in self.args)
            kwargs = dict((k, v() if callable(v) else v) for k, v in self.kwargs.items())
    
            return self.message.format(*args, **kwargs)
    
    N = NewStyleLogMessage
    
    # Neither one of these messages are formatted (or calculated) until they're
    # needed
    
    # Emits "Lazily formatted log entry: 123 foo" in log
    logging.debug(N('Lazily formatted log entry: {0} {keyword}', 123, keyword='foo'))
    
    
    def expensive_func():
        # Do something that takes a long time...
        return 'foo'
    
    # Emits "Expensive log entry: foo" in log
    logging.debug(N('Expensive log entry: {keyword}', keyword=expensive_func))
    

    Все это описано в документации по Python 3 ( https: // docs. питон. орг / 3 / HOWTO / каротаж поваренной. html # formatting-styles ). Тем не менее, он будет работать с Python 2. 6 ( https: // docs. питон. орг / 2. 6 / библиотека / каротаж. html # using-произвольные объекты-как-сообщения ).

    Одним из преимуществ использования этого метода, помимо того факта, что он не зависит от стиля форматирования, является то, что он допускает ленивые значения e. г. функция expensive_func выше. Это обеспечивает более элегантную альтернативу советам, приведенным в документации по Python здесь: https: // docs. питон. орг / 2. 6 / библиотека / каротаж. HTML # оптимизация .

    ответ дан David Sanders, с репутацией 2624, 21.08.2014
  • 8 рейтинг

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

    '{type_names} [a-z]{2}'.format(type_names='triangle|square')
    

    повышает IndexError. В этой ситуации вы можете использовать:

    '%(type_names)s [a-z]{2}' % {'type_names': 'triangle|square'}
    

    Это позволяет избежать записи регулярного выражения как '{type_names} [a-z]{{2}}'. Это может быть полезно, когда у вас есть два регулярных выражения, где один используется один без формата, но объединение обоих форматируется.

    ответ дан Jorge Leitão, с репутацией 5793, 9.04.2015
  • 1 рейтинг

    Для версии на Python & gt; = 3. 6 (см. PEP 498 )

    s1='albha'
    s2='beta'
    
    f'{s1}{s2:>10}'
    
    #output
    'albha      beta'
    
    ответ дан Roushan, с репутацией 1900, 14.02.2018