Multi line string with arguments. How to declare?

Question:

Let’s say I have an extremely long string with arguments that I want to create.
I know you can create a multiline string with

cmd = """line 1
      line 2
      line 3"""

But now lets say I want to pass 1, 2, and 3 as arguments.

This works

cmd = """line %d
      line %d
      line %d""" % (1, 2, 3)

But if I have a super long string with 30+ arguments, how can I possibly pass those arguments in multiple lines? Passing them in a single line defeats the purpose of even trying to create a multiline string.

Thanks to anyone in advance for their help and insight.

Asked By: Quillion

||

Answers:

You could abuse the line continuation properties of the parenthesis ( and the comma ,.

cmd = """line %d
      line %d
      line %d""" % (
      1,
      2,
      3)
Answered By: Frédéric Hamidi

This works for me:

cmd = """line %d
      line %d
      line %d""" % (
          1,
          2,
          3
      )
Answered By: Cameron

To have the arguments in the same line they are inserted, you could do it like this:

cmd = "line %dn"%1 +
      "line %dn"%2 +
      "line %dn"%3

[EDIT:] In reply to the first comment I came up with this:

cmd = "n".join([
      "line %d"%1,
      "line %d"%2,
      "line %d"%3])
Answered By: Qlaus

You could use the str.format() function, that allows named arguments, so:

'''line {0}
line {1}
line {2}'''.format(1,2,3)

You could of course extend this using Python’s *args syntax to allow you to pass in a tuple or list:

args = (1,2,3)
'''line {0}
line {1}
line {2}'''.format(*args)

If you can intelligently name your arguments, the most robust solution (though the most typing-intensive one) would be to use Python’s **kwargs syntax to pass in a dictionary:

args = {'arg1':1, 'arg2':2, 'arg3':3}
'''line {arg1}
line {arg2}
line {arg3}'''.format(**args)

For more information on the str.format() mini-language, go here.

Answered By: Chinmay Kanchi

One more variant with the string.format()-Function.

s = "{0} " 
    "{1} " 
    "{2}" 
    .format("Hello", "world", "from a multiline string")    
print(s)
Answered By: elim

The easiest way might be to use literal string interpolation (available from Python 3.6 onwards and assuming all the arguments are in scope).

cmd = f"""line {1}
      line {2}
      line {3}"""
Answered By: Michael Mauderer

Update 19 Oct. 2020: though my answer here is still insightful, informative, and worth-reading, I have a better answer here now which relies on the really useful textwrap.dedent() function.


As @Chinmay Kanchi says, you can do:

'''line {0}
line {1}
line {2}'''.format(1,2,3)

However, I think it looks goofy with alignment that has to be full-left-aligned on new lines, especially when you are doing this already several levels indented, so I’d prefer it to be written more like this:

'''line {0}
   line {1}
   line {2}'''.format(1,2,3)

That works, BUT IS WRONG! It interprets all spaces to the left of line {1} and line {2} as real spaces, so printing it will look goofy:

1
   2
   3

Instead of

1
2
3

So, a work-around is to use the + operator to concatenate, and parenthesis around the concatenated string, as well as explicit new-line (n) characters, like this:

('line {0}n' + 
 'line {1}n' +
 'line {2}').format(1,2,3)

Perfect (in my opinion)! Now it looks nice and aligned in both the source code and the actual string if you print it.

Full example:

UGLY Source Code!

num1 = 7
num2 = 100
num3 = 75.49

# Get some levels of indentation to really show the effect well.
# THIS IS *UGLY*! Notice the weird forced-left-align thing for the string I want to print!
if (True):
    if (True):
        if (True):
            # AAAAAH! This is hard to look at!
            print('''num1 = {}
num2 = {}
num3 = {}'''.format(num1, num2, num3))

            # More lines of code go here
            # etc
            # etc

Output:

num1 = 7
num2 = 100
num3 = 75.49

Pretty Example! Ahh, so nice to look at in the source code. 🙂

This is what I prefer.

# Get some levels of indentation to really show the effect well.
if (True):
    if (True):
        if (True):
            # IMPORTANT: the extra set of parenthesis to tie all of the concatenated strings together here is *required*!
            print(('num1 = {}n' + 
                   'num2 = {}n' + 
                   'num3 = {}')
                   .format(num1, num2, num3))

            # More lines of code go here
            # etc
            # etc

Output:

num1 = 7
num2 = 100
num3 = 75.49

Update 21 May 2019: Sometimes the "ugly" multi-line string really is the best way to go!

So, I’ve been using Python to auto-generate C header and source (.h/.c) files from text-based configuration files, and after doing a fair amount of this I’ve concluded that the benefits of simply copy-pasting large chunks of text from a configuration file into my Python script outweigh any "ugliness" factors.

Therefore, I’ve determined that the following is my preferred way to do it when a large, multi-line copy-pasted string is required, for example:

Option 1:

  • Use parenthesis around the whole long string to allow the opening """ to be on a new line

    Get some levels of indentation to still show the "ugliness" effect.

    if (True):
    if (True):
    if (True):
    header = (
    """
    /*
    my custom file header info here
    */

    #pragma once

    #include "{}"

    const {} {};
    """).format(include, struct_t, struct)

              print("header =" + header)
    

Option 2:

  • No parenthesis, but still put the closing """ on its own line

    Get some levels of indentation to still show the "ugliness" effect.

    if (True):
    if (True):
    if (True):
    header = """
    /*
    my custom file header info here
    */

    #pragma once

    #include "{}"

    const {} {};
    """.format(include, struct_t, struct)

              print("header =" + header)
    

Option 3:

  • No parenthesis around the whole string, and put the closing """ on the same line as the string contents to prevent adding a (potentially undesirable) n at the end.

  • However, put the remainder of format( on a new line (or on many new lines) in case it is long.

    Get some levels of indentation to still show the "ugliness" effect.

    if (True):
    if (True):
    if (True):
    header = """
    /*
    my custom file header info here
    */

    #pragma once

    #include "{}"

    const {} {};""".format(
    include, struct_t, struct) # indentation here can literally be anything, but I like to indent 1 level; since it’s inside parenthesis, however, it doesn’t matter

              print("header =" + header)
    

Output:

  • Options 1 and 2 produce an exactly identical output, with an extra n at the very end of the string, which is ok in most cases
  • Option 3 produces the same exact output as Options 1 and 2 except that it does not have the extra n at the very end of the string, in case that is undesirable for your case
  • Whether you use Option 1, 2, or 3 really doesn’t matter–it’s just user preference at this point, other than the extra n as noted just above

This is what is printed by Options 1, 2, and 3 above:

/*
my custom file header info here
*/

#pragma once

#include "<stdint.h>"

const my_struct_t my_struct;


PUTTING IT ALL TOGETHER: a mix of the "pretty" and "ugly" methods together to get the best result in this demo of printing docstring documentation for your module!

Here’s a basic example of using both the "pretty" and the "ugly" multi-line string methods presented above in order to get the best benefits of each. This also shows how to use and print module "docstrings" to document your module. Notice how the """-based multi-line technique gives us great spacing because the way I’ve done it below there is an automatic newline (n) after the opening """ and before the closing """ since that’s how the string is written.

# PRETTY, AND GOOD.
print("nn" + 
      "########################n" + 
      "PRINT DOCSTRING DEMO:n" + 
      "########################")

import sys

def printDocstrings():
    """
    Print all document strings for this module, then exit.
    Params:  NA
    Returns: NA
    """

    # A LITTLE BIT UGLY, BUT GOOD! THIS WORKS GREAT HERE!
    print("""
---------------------
Module Documentation:
---------------------
printDocstrings:{}
myFunc1:{}
class Math:{}
    __init__:{}
    add:{}
    subtract:{}""".format(
        printDocstrings.__doc__,
        myFunc1.__doc__,
        Math.__doc__,
        Math.__init__.__doc__,
        Math.add.__doc__,
        Math.subtract.__doc__))

    sys.exit()

def myFunc1():
    """
    Do something.
    Params:  NA
    Returns: NA
    """
    pass

class Math:
    """
    A basic "math" class to add and subtract
    """

    def __init__(self):
        """
        New object initialization function.
        Params:  NA
        Returns: NA
        """
        pass

    def add(a, b):
        """
        Add a and b together.
        Params:  a   1st number to add
                 b   2nd number to add
        Returns: the sum of a + b
        """
        return a + b

    def subtract(a, b):
        """
        Subtract b from a.
        Params:  a   number to subtract from
                 b   number to subtract
        Returns: the result of a - b
        """
        return a - b

printDocstrings() 

Output:
– Notice how pretty and well-formatted it all automatically is, as the tabs, newlines, and spacing of your docstrings are all automatically preserved when you print them this way!

  
########################  
PRINT DOCSTRING DEMO:  
########################  
  
---------------------  
Module Documentation:  
---------------------  
printDocstrings:  
    Print all document strings for this module, then exit.  
    Params:  NA  
    Returns: NA  
      
myFunc1:  
    Do something.  
    Params:  NA  
    Returns: NA  
      
class Math:  
    A basic "math" class to add and subtract  
      
    __init__:  
        New object initialization function.  
        Params:  NA  
        Returns: NA  
          
    add:  
        Add a and b together.  
        Params:  a   1st number to add  
                 b   2nd number to add  
        Returns: the sum of a + b  
          
    subtract:  
        Subtract b from a.  
        Params:  a   number to subtract from  
                 b   number to subtract  
        Returns: the result of a - b  
          
  

References:

  1. Python docstrings: https://www.geeksforgeeks.org/python-docstrings/
  • Note: you can also use the help() method to access a module or class’s documentation (but in an interactive manner), as shown in the link above, like this:

         help(Math)  # to interactively display Class docstring
         help(Math.add)  # to interactively display method's docstring 
    
Answered By: Gabriel Staples

Here is the simplest version, which is also IDE-friendly in terms of checking format arguments:

cmd = (
    'line {}n'
    'line {}n'
    'line {}n'
    .format(1, 2, 3))

Multiline arguments version:

cmd = (
    'line {}n'
    'line {}n'
    'line {}n'
    .format(
        'very very very very very very very very very long 1',
        'very very very very very very very very very long 2',
        'very very very very very very very very very long 3',
    )
)
Answered By: George Sovetov

You may use textwrap.dedent to remove leading spaces from lines:

import textwrap

cmd = str.strip(textwrap.dedent(
    '''
        line {}
            line with indent
        line {}
        line {}
    '''
    .format(1, 2, 3)))

This results in:

line 1
    line with indent
line 2
line 3
Answered By: George Sovetov

Summary

Jump straight down and look at Examples 1 and 4 below.

Full answer:

I just barely learned about the Python textwrap module, with its really handy textwrap.dedent() function, and considering it’s been around since Python 2.7, I can’t believe it isn’t more popular!

Using textwrap.dedent() around a multi-line string solves all of the problems of my previous answer!

Here’s the official documentation on it (emphasis added):

textwrap.dedent(text)

Remove any common leading whitespace from every line in text.

This can be used to make triple-quoted strings line up with the left edge of the display, while still presenting them in the source code in indented form.

Note that tabs and spaces are both treated as whitespace, but they are not equal: the lines " hello" and "thello" are considered to have no common leading whitespace.

Lines containing only whitespace are ignored in the input and normalized to a single newline character in the output.

For example:

def test():
    # end first line with  to avoid the empty line!
    s = '''
    hello
      world
    '''
    print(repr(s))          # prints '    hellon      worldn    '
    print(repr(dedent(s)))  # prints 'hellon  worldn'

For all examples

import textwrap

Example 1

So, instead of this, as the most-upvoted answer states (this loses the nice, clean, indentation):

cmd = '''line {0}
line {1}
line {2}'''.format(1,2,3)

print(cmd)

Do this (and KEEP the nice, clean, indentation)!

import textwrap

cmd = textwrap.dedent('''
    line {0}
    line {1}
    line {2}''').format(1,2,3)

print(cmd)

OR, using Python3’s new-and-improved "f" format strings instead of the .format() method!:

import textwrap

var0 = 1
var1 = 2
var2 = 3
cmd = textwrap.dedent(f'''
    line {var0}
    line {var1}
    line {var2}''')

print(cmd)

Example 2

If you have many arguments to the format() function, you can put them on multiple lines if desired. Notice that the format() arguments take up two lines here:

cmd = textwrap.dedent('''
    line {0}
    line {1}
    line {2}
    line {3}
    line {4}
    line {5}
    line {6}
    line {7}
    line {8}
    line {9}
    line {10}
    line {11}
    line {12}
    line {13}
    line {14}
    line {15}
    line {16}
    line {17}
    line {18}
    line {19}''').format(
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
        11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
    )

print(cmd)

And of course, if the format() arguments are really long, you can put each argument on its own line too:

cmd = textwrap.dedent('''
    line {0}
    line {1}
    line {2}
    line {3}
    line {4}
    line {5}
    line {6}
    line {7}
    line {8}
    line {9}
    line {10}
    line {11}
    line {12}
    line {13}
    line {14}
    line {15}
    line {16}
    line {17}
    line {18}
    line {19}''').format(
        100000000000000000000000000000000000000000000000000000000000000000001,
        100000000000000000000000000000000000000000000000000000000000000000002,
        100000000000000000000000000000000000000000000000000000000000000000003,
        100000000000000000000000000000000000000000000000000000000000000000004,
        100000000000000000000000000000000000000000000000000000000000000000005,
        100000000000000000000000000000000000000000000000000000000000000000006,
        100000000000000000000000000000000000000000000000000000000000000000007,
        100000000000000000000000000000000000000000000000000000000000000000008,
        100000000000000000000000000000000000000000000000000000000000000000009,
        100000000000000000000000000000000000000000000000000000000000000000010,
        100000000000000000000000000000000000000000000000000000000000000000011,
        100000000000000000000000000000000000000000000000000000000000000000012,
        100000000000000000000000000000000000000000000000000000000000000000013,
        100000000000000000000000000000000000000000000000000000000000000000014,
        100000000000000000000000000000000000000000000000000000000000000000015,
        100000000000000000000000000000000000000000000000000000000000000000016,
        100000000000000000000000000000000000000000000000000000000000000000017,
        100000000000000000000000000000000000000000000000000000000000000000018,
        100000000000000000000000000000000000000000000000000000000000000000019,
        100000000000000000000000000000000000000000000000000000000000000000020,
    )

print(cmd)

Example 3

And instead of this, as I stated in my original answer (which keeps nice-looking indentation but is a bit tedious to use):

print("nn" + 
      "########################n" + 
      "PRINT DOCSTRING DEMO:n" + 
      "########################")

…you can now do this!–which allows my multi-line strings, when printed, to "line up with the left edge of the display, while still presenting them in the source code in indented form" (see official documentation):

# Note: use the `` below to prevent the implicit newline right after it from being printed.
print(textwrap.dedent("""

      ########################
      PRINT DOCSTRING DEMO:
      ########################
      """))

Example 4

And instead of this, which has some ugly-looking lack-of-indentation right in the middle of it:

def printDocstrings1():
    """
    Print all document strings for this module, then exit.
    Params:  NA
    Returns: NA
    """

    # A LITTLE BIT UGLY, BUT IT WORKS.
    print("""
---------------------
Module Documentation:
---------------------
printDocstrings:{}
myFunc1:{}
class Math:{}
    __init__:{}
    add:{}
    subtract:{}""".format(
        printDocstrings1.__doc__,
        myFunc1.__doc__,
        Math.__doc__,
        Math.__init__.__doc__,
        Math.add.__doc__,
        Math.subtract.__doc__))

do this, which uses textwrap.dedent() to keep nice-looking indentation all throughout!:

def printDocstrings2():
    """
    Print all document strings for this module, then exit.
    Params:  NA
    Returns: NA
    """

    # MUCH CLEANER! Now I can have the proper indentation on the left withOUT
    # it printing that indentation!
    print(textwrap.dedent("""
    ---------------------
    Module Documentation:
    ---------------------
    printDocstrings:{}
    myFunc1:{}
    class Math:{}
        __init__:{}
        add:{}
        subtract:{}""").format(
            printDocstrings2.__doc__,
            myFunc1.__doc__,
            Math.__doc__,
            Math.__init__.__doc__,
            Math.add.__doc__,
            Math.subtract.__doc__))

Run the code above

You can run my test code above in my eRCaGuy_hello_world GitHub repo here: textwrap_practice_1.py.

Run command:

./textwrap_practice_1.py

OR:

python3 textwrap_practice_1.py
Answered By: Gabriel Staples
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.