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

后端 未结 16 2764
青春惊慌失措
青春惊慌失措 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:42

    For python version >= 3.6 (see PEP 498)

    s1='albha'
    s2='beta'
    
    f'{s1}{s2:>10}'
    
    #output
    'albha      beta'
    
    0 讨论(0)
  • 2020-11-21 04:45

    But please be careful, just now I've discovered one issue when trying to replace all % with .format in existing code: '{}'.format(unicode_string) will try to encode unicode_string and will probably fail.

    Just look at this Python interactive session log:

    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 is just a string (called 'byte array' in Python3) and u is a Unicode string (called 'string' in Python3):

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

    When you give a Unicode object as a parameter to % operator it will produce a Unicode string even if the original string wasn't Unicode:

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

    but the .format function will raise "UnicodeEncodeError":

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

    and it will work with a Unicode argument fine only if the original string was Unicode.

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

    or if argument string can be converted to a string (so called 'byte array')

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

    Python 3.6.7 comparative:

    #!/usr/bin/env python
    import timeit
    
    def time_it(fn):
        """
        Measure time of execution of a function
        """
        def wrapper(*args, **kwargs):
            t0 = timeit.default_timer()
            fn(*args, **kwargs)
            t1 = timeit.default_timer()
            print("{0:.10f} seconds".format(t1 - t0))
        return wrapper
    
    
    @time_it
    def new_new_format(s):
        print("new_new_format:", f"{s[0]} {s[1]} {s[2]} {s[3]} {s[4]}")
    
    
    @time_it
    def new_format(s):
        print("new_format:", "{0} {1} {2} {3} {4}".format(*s))
    
    
    @time_it
    def old_format(s):
        print("old_format:", "%s %s %s %s %s" % s)
    
    
    def main():
        samples = (("uno", "dos", "tres", "cuatro", "cinco"), (1,2,3,4,5), (1.1, 2.1, 3.1, 4.1, 5.1), ("uno", 2, 3.14, "cuatro", 5.5),) 
        for s in samples:
            new_new_format(s)
            new_format(s)
            old_format(s)
            print("-----")
    
    
    if __name__ == '__main__':
        main()
    

    Output:

    new_new_format: uno dos tres cuatro cinco
    0.0000170280 seconds
    new_format: uno dos tres cuatro cinco
    0.0000046750 seconds
    old_format: uno dos tres cuatro cinco
    0.0000034820 seconds
    -----
    new_new_format: 1 2 3 4 5
    0.0000043980 seconds
    new_format: 1 2 3 4 5
    0.0000062590 seconds
    old_format: 1 2 3 4 5
    0.0000041730 seconds
    -----
    new_new_format: 1.1 2.1 3.1 4.1 5.1
    0.0000092650 seconds
    new_format: 1.1 2.1 3.1 4.1 5.1
    0.0000055340 seconds
    old_format: 1.1 2.1 3.1 4.1 5.1
    0.0000052130 seconds
    -----
    new_new_format: uno 2 3.14 cuatro 5.5
    0.0000053380 seconds
    new_format: uno 2 3.14 cuatro 5.5
    0.0000047570 seconds
    old_format: uno 2 3.14 cuatro 5.5
    0.0000045320 seconds
    -----
    
    0 讨论(0)
  • 2020-11-21 04:48

    If your python >= 3.6, F-string formatted literal is your new friend.

    It's more simple, clean, and better performance.

    In [1]: params=['Hello', 'adam', 42]
    
    In [2]: %timeit "%s %s, the answer to everything is %d."%(params[0],params[1],params[2])
    448 ns ± 1.48 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
    
    In [3]: %timeit "{} {}, the answer to everything is {}.".format(*params)
    449 ns ± 1.42 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
    
    In [4]: %timeit f"{params[0]} {params[1]}, the answer to everything is {params[2]}."
    12.7 ns ± 0.0129 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
    
    0 讨论(0)
  • 2020-11-21 04:49

    As of Python 3.6 (2016) you can use f-strings to substitute variables:

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

    Note the f" prefix. If you try this in Python 3.5 or earlier, you'll get a SyntaxError.

    See https://docs.python.org/3.6/reference/lexical_analysis.html#f-strings

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

    Yet another advantage of .format (which I don't see in the answers): it can take object properties.

    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'
    

    Or, as a keyword argument:

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

    This is not possible with % as far as I can tell.

    0 讨论(0)
提交回复
热议问题