String formatting: % vs. .format vs. string literal

后端 未结 16 2703
青春惊慌失措
青春惊慌失措 2020-11-21 04:18

Python 2.6 introduced the str.format() method with a slightly different syntax from the existing % operator. Which is better and for what situations?

Pyt

相关标签:
16条回答
  • 2020-11-21 04:58

    But one thing is that also if you have nested curly-braces, won't work for format but % will work.

    Example:

    >>> '{{0}, {1}}'.format(1,2)
    Traceback (most recent call last):
      File "<pyshell#3>", line 1, in <module>
        '{{0}, {1}}'.format(1,2)
    ValueError: Single '}' encountered in format string
    >>> '{%s, %s}'%(1,2)
    '{1, 2}'
    >>> 
    
    0 讨论(0)
  • 2020-11-21 05:00

    As a side note, you don't have to take a performance hit to use new style formatting with logging. You can pass any object to logging.debug, logging.info, etc. that implements the __str__ magic method. When the logging module has decided that it must emit your message object (whatever it is), it calls str(message_object) before doing so. So you could do something like this:

    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))
    

    This is all described in the Python 3 documentation (https://docs.python.org/3/howto/logging-cookbook.html#formatting-styles). However, it will work with Python 2.6 as well (https://docs.python.org/2.6/library/logging.html#using-arbitrary-objects-as-messages).

    One of the advantages of using this technique, other than the fact that it's formatting-style agnostic, is that it allows for lazy values e.g. the function expensive_func above. This provides a more elegant alternative to the advice being given in the Python docs here: https://docs.python.org/2.6/library/logging.html#optimization.

    0 讨论(0)
  • 2020-11-21 05:04

    As I discovered today, the old way of formatting strings via % doesn't support Decimal, Python's module for decimal fixed point and floating point arithmetic, out of the box.

    Example (using 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))
    

    Output:

    0.00000000000000000000000312375239000000009907464850 0.00000000000000000000000312375239000000000000000000

    There surely might be work-arounds but you still might consider using the format() method right away.

    0 讨论(0)
  • 2020-11-21 05:05

    Something that the modulo operator ( % ) can't do, afaik:

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

    result

    12 22222 45 22222 103 22222 6 22222
    

    Very useful.

    Another point: format(), being a function, can be used as an argument in other functions:

    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))
    

    Results in:

    ['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
    
    0 讨论(0)
提交回复
热议问题