1935

I have a very long query. I would like to split it in several lines in Python. A way to do it in JavaScript would be using several sentences and joining them with a + operator (I know, maybe it's not the most efficient way to do it, but I'm not really concerned about performance in this stage, just code readability). Example:

var long_string = 'some text not important. just garbage to' +
                      'illustrate my example';

I tried doing something similar in Python, but it didn't work, so I used \ to split the long string. However, I'm not sure if this is the only/best/pythonicest way of doing it. It looks awkward. Actual code:

query = 'SELECT action.descr as "action", '\
    'role.id as role_id,'\
    'role.descr as role'\
    'FROM '\
    'public.role_action_def,'\
    'public.role,'\
    'public.record_def, '\
    'public.action'\
    'WHERE role.id = role_action_def.role_id AND'\
    'record_def.id = role_action_def.def_id AND'\
    'action.id = role_action_def.action_id AND'\
    'role_action_def.account_id = ' + account_id + ' AND'\
    'record_def.account_id=' + account_id + ' AND'\
    'def_id=' + def_id
Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
Pablo Mescher
  • 26,057
  • 6
  • 30
  • 33
  • 344
    Since your example looks like a SQL block just waiting for an injection attack, another suggestion is to look into a higher level SQL library like SQLAlchemy or something to steer clear of hacking together raw SQL like this. (Perhaps off-topic, but you did ask for "Any suggestions". ;) – John Gaines Jr. May 18 '12 at 22:26
  • 11
    This is "Pythonic way to create **multi-line code** for a long string" To create a string **containing newlines** see [textwrap.dedent](http://stackoverflow.com/a/2504454/673991). – Bob Stein Jan 29 '15 at 17:16
  • I wrote a small package for this. Example here: https://stackoverflow.com/a/56940938/1842491 – Shay Jan 24 '20 at 14:49
  • Related: [How to write very long string that conforms with PEP8 and prevent E501](https://stackoverflow.com/a/1874679/3357935) – Stevoisiak Feb 24 '22 at 18:12
  • @JohnGainesJr. Would the SQL chunk above be resistant to SQL injection attacks if the account_id and def_id were sanitised? I am using Pydantic via FastAPI to ensure user input passes a regex pattern, but if this is not safe it would be good to know. I am not anti-SQLAlchemy, just exploring the space. – Steve Hibbert Aug 16 '23 at 08:33

30 Answers30

3129

Are you talking about multi-line strings? Easy, use triple quotes to start and end them.

s = """ this is a very
        long string if I had the
        energy to type more and more ..."""

You can use single quotes too (3 of them of course at start and end) and treat the resulting string s just like any other string.

NOTE: Just as with any string, anything between the starting and ending quotes becomes part of the string, so this example has a leading blank (as pointed out by @root45). This string will also contain both blanks and newlines.

I.e.,:

' this is a very\n        long string if I had the\n        energy to type more and more ...'

Finally, one can also construct long lines in Python like this:

 s = ("this is a very"
      "long string too"
      "for sure ..."
     )

which will not include any extra blanks or newlines (this is a deliberate example showing what the effect of skipping blanks will result in):

'this is a verylong string toofor sure ...'

No commas required, simply place the strings to be joined together into a pair of parenthesis and be sure to account for any needed blanks and newlines.

Levon
  • 138,105
  • 33
  • 200
  • 191
  • 19
    I prefer to use explicitly the "+" operator for the second method. Not much an hassle and improves readability. – Marco Sulla Aug 14 '14 at 10:49
  • 79
    @LucasMalor The adjacent strings are a compile-time concatenation. Doesn't using the `+` operator make the concatenation happen at runtime? – Joshua Taylor Nov 25 '14 at 15:26
  • 33
    For reference, here are the official docs to this phenomenon: https://docs.python.org/2/reference/lexical_analysis.html#string-literal-concatenation (python 2) and https://docs.python.org/3/reference/lexical_analysis.html#string-literal-concatenation (python 3) – neverendingqs Aug 15 '16 at 13:16
  • 1
    How about + stuff? To mix variables and strings. How do you indent that? –  Sep 12 '16 at 18:10
  • 4
    Your example is good, but I wish it had included demonstrating how to safely and securely embed variable data into the query. Both the OP and @jessee example code show how NOT to do it correctly (they're invitations to SQL attacks). See also: https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-execute.html – Scott Prive Oct 08 '16 at 17:29
  • What about string interpolation? If I want to use variables within this string, how would that work? – Ayush Sharma Jul 17 '17 at 07:02
  • 8
    you can use `textwrap.dedent` to remove unwanted leading whitespace. https://docs.python.org/3/library/textwrap.html#textwrap.dedent – Corey Goldberg Nov 27 '17 at 15:43
  • @JoshuaTaylor Whether you use implicit (adjacent) concatenation or use explicit concatenation with the `+` operator, either results in a compile-time concatenated string literal constant. It doesn't make any difference. In fact, you also get a compile-time string literal when you use the `*` operator with a string literal and an integer literal. – Chris L Nov 28 '17 at 14:17
  • He didn't ask for newlines in the string, bad answer. – aaa90210 Aug 21 '18 at 22:19
  • 1
    Excellent answer. This solved my problem as well -- I have double quotes inside a multi-line string and they are automatically handled correctly. – Blisterpeanuts Dec 16 '20 at 15:41
  • Don't you need commas or + in the example with parentheses? – Lou Jan 19 '21 at 16:57
  • The + operator will give you problems when using string methods. – echefede Apr 29 '21 at 09:20
  • Note: The second method only works when the string is enclosed in `( )`. Otherwise a backslash is needed at the end of each line. – ss7 Jul 01 '21 at 17:03
313

If you don't want a multiline string, but just have a long single line string, you can use parentheses. Just make sure you don't include commas between the string segments (then it will be a tuple).

query = ('SELECT   action.descr as "action", '
         'role.id as role_id,'
         'role.descr as role'
         ' FROM '
         'public.role_action_def,'
         'public.role,'
         'public.record_def, '
         'public.action'
         ' WHERE role.id = role_action_def.role_id AND'
         ' record_def.id = role_action_def.def_id AND'
         ' action.id = role_action_def.action_id AND'
         ' role_action_def.account_id = '+account_id+' AND'
         ' record_def.account_id='+account_id+' AND'
         ' def_id='+def_id)

In a SQL statement like what you're constructing, multiline strings would also be fine. But if the extra white space a multiline string would contain would be a problem, then this would be a good way to achieve what you want.

As noted in the comments, concatenating SQL queries in this way is a SQL injection security risk waiting to happen, so use your database's parameterized queries feature to prevent this. However, I'm leaving the answer as-is otherwise as it directly answers the question asked.

Stabledog
  • 3,110
  • 2
  • 32
  • 43
Jesse
  • 4,814
  • 1
  • 18
  • 9
  • 1
    @Pablo you can even add comments after the `,` – Ashwini Chaudhary May 18 '12 at 22:45
  • 2
    @200OK you mean after `'`? – kon psych Jun 15 '14 at 06:14
  • 3
    Another way to format this string would be to add `.format(...)` after the closing parenthesis. `%` formating notation must work too but I haven't tried it – kon psych Jun 15 '14 at 06:16
  • 7
    Note that each line must end with a string constant, so `' foo '+variable` won't work, but `' foo '+variable+''` will. – yoyo Jul 08 '15 at 06:57
  • 106
    This example is an open door to SQL injection attacks. Please, no one use this on any public-facing application. See the MySQL docs for how to use 'placeholders': https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-execute.html – Scott Prive Oct 08 '16 at 17:30
  • 1
    @Crossfit_and_Beer They're called query parameters, and the queries that have them are called paramterized queries. And every major relational DBMS supports them. – jpmc26 Sep 14 '18 at 23:12
  • 1
    This best answers the title of the question - it is indeed the most Pythonic way to create a multi-line string. There is still an issue with SQL injection, but that wasn't a core part of the question. – cezar Nov 03 '19 at 14:28
189

Breaking lines by \ works for me. Here is an example:

longStr = "This is a very long string " \
        "that I wrote to help somebody " \
        "who had a question about " \
        "writing long strings in Python"
amphibient
  • 29,770
  • 54
  • 146
  • 240
  • 11
    I would prefer either the triple quote notation or wrapping inside () to the \ character – Khanh Hua Jan 03 '16 at 09:32
  • 37
    I strongly advise to put the spaces at the beginning of the following lines instead of at the ending of the followed lines. This way an accidentally missing one is way more obvious (and thus is less likely to happen). – Alfe Dec 20 '17 at 14:39
  • 1
    Also works with variables at the end of lines `longStr = "account: " + account_id + \ ... ` – Vladislav Povorozniuc Dec 05 '19 at 22:56
  • 1
    I am getting following error: `the backslash is redundant between brackets` when I wrote in inside `print()` – alper May 25 '20 at 19:35
  • 3
    @Alfe No need to worry about missing \'s anymore. VScode will have a heart attack if I miss one – Arthur Tarasov Jul 23 '20 at 02:18
  • @ArthurTarasov I didn't worry about the backslashes. My comment what about the spaces _within_ the string. In the answer they are at the end of the first, second, and third line, every time at a different column, hence a missing one can easily be overlooked. I recommend to put them instead at the beginning of the second, third, and fourth line, every time at column 1 of the string, hence neatly above each other so that a missing one is quite obvious and thus unlikely to happen. – Alfe Jul 23 '20 at 21:19
  • VScode = [Visual Studio Code](https://en.wikipedia.org/wiki/Visual_Studio_Code) – Peter Mortensen Feb 19 '21 at 18:30
  • Avoid using backslashes to break up long lines of code. It reduces clarity, makes refactoring more painful, and avoids the root of the problem (you don't know of a better way making your code fit within 79 characters). – Chris Collett Oct 11 '21 at 17:20
  • 3
    Both [PEP 8](https://peps.python.org/pep-0008/#maximum-line-length) and [Black](https://black.readthedocs.io/en/stable/contributing/reference/reference_functions.html#black.linegen.normalize_prefix) discourage using backslashes for line continuation. – Stevoisiak Nov 15 '22 at 15:49
63

I found myself happy with this one:

string = """This is a
very long string,
containing commas,
that I split up
for readability""".replace('\n',' ')
Eero Aaltonen
  • 4,239
  • 1
  • 29
  • 41
  • 56
    Disagree. What if the first line ("string = ...") is heavily indented? One would have to de-dent the following lines to zero indentation, which looks ugly in the middle of an otherwise indented block. – xjcl Apr 14 '17 at 23:51
  • 1
    Well, the majority of my lengthy strings occur at the module level, where this fits nicely. In your case though this would obviously not be the best solution. – Eero Aaltonen Apr 18 '17 at 07:37
  • 1
    I like this approach because it privileges reading. In cases where we have long strings there is no way... Depending on the level of indentation you are in and still limited to 80 characters per line... Well... No need to say anything else. In my view the python style guides are still very vague. Thanks! – Eduardo Lucio Jun 01 '17 at 12:39
  • 1
    This would be so ugly if it is used under a module, I have to as also `.replace('\t','')` – alper May 25 '20 at 19:39
  • 2
    If you care about code-folding, this would break it in most editors. – Keto Oct 17 '20 at 07:35
63

I find that when building long strings, you are usually doing something like building an SQL query, in which case this is best:

query = ' '.join((  # Note double parentheses. join() takes an iterable
    "SELECT foo",
    "FROM bar",
    "WHERE baz",
))

What Levon suggested is good, but it might be vulnerable to mistakes:

query = (
    "SELECT foo"
    "FROM bar"
    "WHERE baz"
)

query == "SELECT fooFROM barWHERE baz"  # Probably not what you want
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
darkfeline
  • 9,404
  • 5
  • 31
  • 32
  • 14
    +1 Relieves code-reviewer from having to assiduously check the right end of every line for **inadequate whitespace**. The OP committed this mistake several times, as noted by @KarolyHorvath. – Bob Stein Jan 30 '15 at 15:53
  • 3
    When reviewing multiline strings coded in similar fashion, I require adequate whitespace on the *left* end of every line for easy confirmation. – Umbrella Sep 21 '16 at 14:13
  • 4
    @BobStein-VisiBone Code reviews should not be about syntax errors or small bugs like this, they should be about substance. If somebody is putting code up for review that has syntax errors (and thus won't run either at all or in certain situations) then something is seriously wrong. It's not hard to run lint before you commit. If the person hasn't noticed their program doesn't run correctly because they made such an obvious mistake, they shouldn't be committing. – Charles D Pantoga Oct 17 '16 at 18:24
  • 1
    Agreed @CharlesAddis, code reviews should come after automated methods, e.g. lint, syntax highlighting, etc. However some white-space-missing bugs may not be caught that way. Avail yourself of all reasonable advantages in guarding against bugs, I suggest. – Bob Stein Oct 17 '16 at 18:32
  • Added benefit is that you can quickly out-comment lines. – Ideogram Feb 23 '22 at 11:52
57

This approach uses:

  • almost no internal punctuation by using a triple quoted string
  • strips away local indentation using the inspect module
  • uses Python 3.6 formatted string interpolation ('f') for the account_id and def_id variables.

This way looks the most Pythonic to me.

import inspect

query = inspect.cleandoc(f'''
    SELECT action.descr as "action",
    role.id as role_id,
    role.descr as role
    FROM
    public.role_action_def,
    public.role,
    public.record_def,
    public.action
    WHERE role.id = role_action_def.role_id AND
    record_def.id = role_action_def.def_id AND
    action.id = role_action_def.action_id AND
    role_action_def.account_id = {account_id} AND
    record_def.account_id={account_id} AND
    def_id={def_id}'''
)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Christopher Bruns
  • 9,160
  • 7
  • 46
  • 61
  • 8
    Note: [`inspect.cleandoc` is slightly nicer](https://docs.python.org/3/library/inspect.html#inspect.cleandoc) than `textwrap.dedent`, as it doesn't require the first line to be empty with a line continuation character at the end. – ShadowRanger Jan 29 '19 at 21:19
  • 3
    @ShadowRanger Wow I never used cleandoc before. I updated my answer and will in future use `inspect.cleandoc` for this. – Christopher Bruns Jan 29 '19 at 21:54
  • 1
    This worked great for me! Gets rid of the spaces that are added from the editor during the ''' quote process! – Joseph Astrahan Sep 27 '20 at 18:12
  • 5
    Although it looks really nice, I think this approach will be vulnerable to SQL injection. Sadly f-string is not good with SQL queries. From other comments, it is better to use `cursor.execute` instead https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-execute.html – jackblk Feb 22 '21 at 08:43
41

You can also include variables when using """ notation:

foo = '1234'

long_string = """fosdl a sdlfklaskdf as
as df ajsdfj asdfa sld
a sdf alsdfl alsdfl """ +  foo + """ aks
asdkfkasdk fak"""

A better way is, with named parameters and .format():

body = """
<html>
<head>
</head>
<body>
    <p>Lorem ipsum.</p>
    <dl>
        <dt>Asdf:</dt>     <dd><a href="{link}">{name}</a></dd>
    </dl>
    </body>
</html>
""".format(
    link='http://www.asdf.com',
    name='Asdf',
)

print(body)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
gjgjgj
  • 841
  • 8
  • 11
  • 2
    Using [f strings](https://stackoverflow.com/a/50746619/1705829) here seems more natural and easy. – Timo Mar 03 '21 at 19:30
  • 1
    If `{link}` or `{name}` was used more than once I'd prefer `.format()`; however if the variable names are long I prefer `.format()` too – Yzmir Ramirez Apr 15 '23 at 23:45
30

In Python >= 3.6 you can use Formatted string literals (f string)

query= f'''SELECT   action.descr as "action"
    role.id as role_id,
    role.descr as role
    FROM
    public.role_action_def,
    public.role,
    public.record_def,
    public.action
    WHERE role.id = role_action_def.role_id AND
    record_def.id = role_action_def.def_id AND
    action.id = role_action_def.action_id AND
    role_action_def.account_id = {account_id} AND
    record_def.account_id = {account_id} AND
    def_id = {def_id}'''
Vlad Bezden
  • 83,883
  • 25
  • 248
  • 179
24

I find textwrap.dedent the best for long strings as described here:

def create_snippet():
    code_snippet = textwrap.dedent("""\
        int main(int argc, char* argv[]) {
            return 0;
        }
    """)
    do_something(code_snippet)
fredrik
  • 9,631
  • 16
  • 72
  • 132
23

For example:

sql = ("select field1, field2, field3, field4 "
       "from table "
       "where condition1={} "
       "and condition2={}").format(1, 2)

Output: 'select field1, field2, field3, field4 from table
         where condition1=1 and condition2=2'

If the value of the condition should be a string, you can do it like this:

sql = ("select field1, field2, field3, field4 "
       "from table "
       "where condition1='{0}' "
       "and condition2='{1}'").format('2016-10-12', '2017-10-12')

Output: "select field1, field2, field3, field4 from table where
         condition1='2016-10-12' and condition2='2017-10-12'"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
pangpang
  • 8,581
  • 11
  • 60
  • 96
21

Others have mentioned the parentheses method already, but I'd like to add that with parentheses, inline comments are allowed.

Comment on each fragment:

nursery_rhyme = (
    'Mary had a little lamb,'          # Comments are great!
    'its fleece was white as snow.'
    'And everywhere that Mary went,'
    'her sheep would surely go.'       # What a pesky sheep.
)

Comment not allowed after continuation:

When using backslash line continuations (\ ), comments are not allowed. You'll receive a SyntaxError: unexpected character after line continuation character error.

nursery_rhyme = 'Mary had a little lamb,' \  # These comments
    'its fleece was white as snow.'       \  # are invalid!
    'And everywhere that Mary went,'      \
    'her sheep would surely go.'
# => SyntaxError: unexpected character after line continuation character

Better comments for Regex strings:

Based on the example from https://docs.python.org/3/library/re.html#re.VERBOSE,

a = re.compile(
    r'\d+'  # the integral part
    r'\.'   # the decimal point
    r'\d*'  # some fractional digits
)
# Using VERBOSE flag, IDE usually can't syntax highight the string comment.
a = re.compile(r"""\d +  # the integral part
                   \.    # the decimal point
                   \d *  # some fractional digits""", re.X)
ddrscott
  • 539
  • 5
  • 3
19

The PEP 8 Style Guide recommends using parenthesis:

The preferred way of wrapping long lines is by using Python's implied line continuation inside parentheses, brackets and braces. Long lines can be broken over multiple lines by wrapping expressions in parentheses. These should be used in preference to using a backslash for line continuation.

Example:

long_string = (
    "This is a lengthy string that takes up a lot of space. I am going to "
    "keep on typing words to fill up more and more space to show how you can "
    "split the string across multiple lines."
)
Stevoisiak
  • 23,794
  • 27
  • 122
  • 225
18

As a general approach to long strings in Python, you can use triple quotes, split and join:

_str = ' '.join('''Lorem ipsum dolor sit amet, consectetur adipiscing
        elit, sed do eiusmod tempor incididunt ut labore et dolore
        magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
        ullamco laboris nisi ut aliquip ex ea commodo.'''.split())

Output:

'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.'

With regard to OP's question relating to a SQL query, the answer below disregards the correctness of this approach to building SQL queries and focuses only on building long strings in a readable and aesthetic way without additional imports. It also disregards the computational load this entails.

Using triple quotes, we build a long and readable string which we then break up into a list using split() thereby stripping the white space and then join it back together with ' '.join(). Finally we insert the variables using the format() command:

account_id = 123
def_id = 321

_str = '''
    SELECT action.descr AS "action", role.id AS role_id, role.descr AS role
    FROM public.role_action_def, public.role, public.record_def, public.action
    WHERE role.id = role_action_def.role_id
    AND record_def.id = role_action_def.def_id
    AND' action.id = role_action_def.action_id
    AND role_action_def.account_id = {}
    AND record_def.account_id = {}
    AND def_id = {}
    '''

query = ' '.join(_str.split()).format(account_id, account_id, def_id)

Produces:

SELECT action.descr AS "action", role.id AS role_id, role.descr AS role FROM public.role_action_def, public.role, public.record_def, public.action WHERE role.id = role_action_def.role_id AND record_def.id = role_action_def.def_id AND action.id = role_action_def.action_id AND role_action_def.account_id = 123 AND record_def.account_id=123 AND def_id=321

This approach is not in line with PEP 8, but I find it useful at times.

Please note that the curly brackets in the original string are used by the format() function.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rasmus Groth
  • 321
  • 2
  • 7
15

I personally find the following to be the best (simple, safe and Pythonic) way to write raw SQL queries in Python, especially when using Python's sqlite3 module:

query = '''
    SELECT
        action.descr as action,
        role.id as role_id,
        role.descr as role
    FROM
        public.role_action_def,
        public.role,
        public.record_def,
        public.action
    WHERE
        role.id = role_action_def.role_id
        AND record_def.id = role_action_def.def_id
        AND action.id = role_action_def.action_id
        AND role_action_def.account_id = ?
        AND record_def.account_id = ?
        AND def_id = ?
'''
vars = (account_id, account_id, def_id)   # a tuple of query variables
cursor.execute(query, vars)   # using Python's sqlite3 module

Pros

  • Neat and simple code (Pythonic!)
  • Safe from SQL injection
  • Compatible with both Python 2 and Python 3 (it's Pythonic after all)
  • No string concatenation required
  • No need to ensure that the right-most character of each line is a space

Cons

  • Since variables in the query are replaced by the ? placeholder, it may become a little difficult to keep track of which ? is to be substituted by which Python variable when there are lots of them in the query.
Faheel
  • 2,435
  • 24
  • 33
  • Note, I haven't tested this, but you can probably avoid the question mark confusion by replacing them with "{0} {1} {2}" in the relevant places and then changing the last line to `cursor.execute(query.format(vars))`. That should take care of your only "con" (I hope). – Ben Mar 31 '18 at 12:28
  • Yes, using `format` would be nice but I'm not sure whether the query string formatted that way would be safe from SQL injection. – Faheel Apr 02 '18 at 08:31
  • Yeah, that's a fair point and it could certainly get a bit tricky. Perhaps testing it on something entirely expendable would be wise ... no doubt a Comp. Sci. undergrad will wander past soon enough. ;) – Ben Apr 04 '18 at 02:15
  • 3
    @Ben if you do `cursor.execute(query.format(vars))` you do not profit from prepared statements anymore so you are vulnerable to many kind of problems, starting with the fact that if the parameters are not just numbers you need to double quote them in the SQL query. – Patrick Mevzek Aug 30 '18 at 21:51
14

Adding to @Levon's answer....

1. Create a multiline string like this:

paragraph = """this is a very
        long string if I had the
        energy to type more and more ..."""

print(paragraph)

Output:

'this is a very\n        long string if I had the\n        energy to type more and more ...'

This string will have newlines and blank spaces. So remove them.

2. Remove extra spaces using regex

paragraph = re.sub('\s+', ' ', paragraph)
print(paragraph)

Ouput:

'this is a very long string if I had the energy to type more and more ...'
user41855
  • 917
  • 8
  • 15
13

tl;dr: Use """\ and """ to wrap the string, as in

string = """\
This is a long string
spanning multiple lines.
"""

From the official Python documentation:

String literals can span multiple lines. One way is using triple-quotes: """...""" or '''...'''. End of lines are automatically included in the string, but it’s possible to prevent this by adding a \ at the end of the line. The following example:

print("""\
Usage: thingy [OPTIONS]
     -h                        Display this usage message
     -H hostname               Hostname to connect to
""")

produces the following output (note that the initial newline is not included):

Usage: thingy [OPTIONS]
     -h                        Display this usage message
     -H hostname               Hostname to connect to
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Flow
  • 23,572
  • 15
  • 99
  • 156
6

I usually use something like this:

text = '''
    This string was typed to be a demo
    on how could we write a multi-line
    text in Python.
'''

If you want to remove annoying blank spaces in each line, you could do as follows:

text = '\n'.join(line.lstrip() for line in text.splitlines())
U13-Forward
  • 69,221
  • 14
  • 89
  • 114
  • 2
    Look into Python's [`textwrap.dedent`](https://github.com/python/cpython/blob/master/Lib/textwrap.py#L414) function, which is in the standard library, it has the functionality you need. – bjd2385 Jun 21 '18 at 18:10
  • @bjd2385: [`inspect.cleandoc`](https://docs.python.org/3/library/inspect.html#inspect.cleandoc) is slightly nicer (less finicky about whether or not text appears on the same line as the open quotes, doesn't require explicit line continuation characters). – ShadowRanger Feb 12 '20 at 00:52
6

Ummm.

I know it's been a long time since this question got posted. But I just found the style I would like to use to assign long and multiline strings to variables in my projects. This takes a bit of extra runtime, but still preserves the beauty of the code, even if the variable I am assigning my string to is heavily indented.

    # Suppose the following code is heavily indented
    line3header = "Third"

    variable = fr"""

First line.
Second line.
{line3header} line.
{{}} line.
...
The last line.

    """.strip()
    """A variable whose name is Variable.

    You can even add a docstring here.
    """

    variable = variable.format("Fourth")
    print(variable)
    variable += "\n"
    print(variable, end="")

There it goes.

Rick
  • 69
  • 1
  • 3
5

Your actual code shouldn't work; you are missing white spaces at the end of "lines" (for example, role.descr as roleFROM...).

There are triple quotes for multiline strings:

string = """line
  line2
  line3"""

It will contain the line breaks and extra spaces, but for SQL that's not a problem.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
5

Try something like this. Like in this format it will return you a continuous line like you have successfully enquired about this property:

"message": f'You have successfully inquired about '
           f'{enquiring_property.title} Property owned by '
           f'{enquiring_property.client}'
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kelvin Onkundi
  • 139
  • 2
  • 2
5

Combining the ideas from:

Levon or Jesse, Faheel and ddrscott

with my formatting suggestion, you could write your query as:

query = ('SELECT'
             ' action.descr as "action"'
             ',role.id as role_id'
             ',role.descr as role'
         ' FROM'
             ' public.role_action_def'
             ',public.role'
             ',public.record_def'
             ',public.action'
         ' WHERE'
             ' role.id = role_action_def.role_id'
             ' AND'
             ' record_def.id = role_action_def.def_id'
             ' AND'
             ' action.id = role_action_def.action_id'
             ' AND'
             ' role_action_def.account_id = ?' # account_id
             ' AND'
             ' record_def.account_id = ?'      # account_id
             ' AND'
             ' def_id = ?'                     # def_id
         )

 vars = (account_id, account_id, def_id)     # A tuple of the query variables
 cursor.execute(query, vars)                 # Using Python's sqlite3 module

Or like:

vars = []
query = ('SELECT'
             ' action.descr as "action"'
             ',role.id as role_id'
             ',role.descr as role'
         ' FROM'
             ' public.role_action_def'
             ',public.role'
             ',public.record_def'
             ',public.action'
         ' WHERE'
             ' role.id = role_action_def.role_id'
             ' AND'
             ' record_def.id = role_action_def.def_id'
             ' AND'
             ' action.id = role_action_def.action_id'
             ' AND'
             ' role_action_def.account_id = '
                 vars.append(account_id) or '?'
             ' AND'
             ' record_def.account_id = '
                 vars.append(account_id) or '?'
             ' AND'
             ' def_id = '
                 vars.append(def_id) or '?'
         )

 cursor.execute(query, tuple(vars))  # Using Python's sqlite3 module

Which could be interesting together with 'IN' and 'vars.extend(options) or n_options(len(options))', where:

def n_options(count):
    return '(' + ','.join(count*'?') + ')'

Or with the hint from darkfeline, that you might still make mistakes with those leading spaces and separators and also with named placeholders:

SPACE_SEP = ' '
COMMA_SEP = ', '
AND_SEP   = ' AND '

query = SPACE_SEP.join((
    'SELECT',
        COMMA_SEP.join((
        'action.descr as "action"',
        'role.id as role_id',
        'role.descr as role',
        )),
    'FROM',
        COMMA_SEP.join((
        'public.role_action_def',
        'public.role',
        'public.record_def',
        'public.action',
        )),
    'WHERE',
        AND_SEP.join((
        'role.id = role_action_def.role_id',
        'record_def.id = role_action_def.def_id',
        'action.id = role_action_def.action_id',
        'role_action_def.account_id = :account_id',
        'record_def.account_id = :account_id',
        'def_id = :def_id',
        )),
    ))

vars = {'account_id':account_id,'def_id':def_id}  # A dictionary of the query variables
cursor.execute(query, vars)                       # Using Python's sqlite3 module

See documentation of Cursor.execute-function.

"This is the [most Pythonic] way!" - ...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
e.d.n.a
  • 191
  • 1
  • 6
4

You can also place the SQL statement in a separate file, action.sql, and load it in the .py file with:

with open('action.sql') as f:
   query = f.read()

So the SQL statements will be separated from the Python code. If there are parameters in the SQL statement which needs to be filled from Python, you can use string formatting (like %s or {field}).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mrijken
  • 128
  • 5
3

Another option that I think is more readable when the code (e.g., a variable) is indented and the output string should be a one-liner (no newlines):

def some_method():

    long_string = """
A presumptuous long string
which looks a bit nicer
in a text editor when
written over multiple lines
""".strip('\n').replace('\n', ' ')

    return long_string
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Eyal Levin
  • 16,271
  • 6
  • 66
  • 56
3

"À la" Scala way (but I think is the most Pythonic way as the OP demands):

description = """
            | The intention of this module is to provide a method to
            | pass meta information in markdown_ header files for
            | using it in jinja_ templates.
            |
            | Also, to provide a method to use markdown files as jinja
            | templates. Maybe you prefer to see the code than
            | to install it.""".replace('\n            | \n','\n').replace('            | ',' ')

If you want final str without jump lines, just put \n at the start of the first argument of the second replace:

.replace('\n            | ',' ')`.

Note: the white line between "...templates." and "Also, ..." requires a white space after the |.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
victe
  • 516
  • 6
  • 8
3

I know it's a rather old question, but Python has changed in the meantime and I don't see this answer, so here we go.

Another way is to use \ to cut the current line and move to another:

print("This line will \
get carried over to\
 the new line.\
Notice how this\
word will be together because \
of no space around it")
1

I use a recursive function to build complex SQL queries. This technique can generally be used to build large strings while maintaining code readability.

# Utility function to recursively resolve SQL statements.
# CAUTION: Use this function carefully, Pass correct SQL parameters {},
# TODO: This should never happen but check for infinite loops
def resolveSQL(sql_seed, sqlparams):
    sql = sql_seed % (sqlparams)
    if sql == sql_seed:
        return ' '.join([x.strip() for x in sql.split()])
    else:
        return resolveSQL(sql, sqlparams)

P.S.: Have a look at the awesome python-sqlparse library to pretty print SQL queries if needed.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sandeep
  • 28,307
  • 3
  • 32
  • 24
1

From the official Python documentation:

String literals can span multiple lines. One way is using triple-quotes: """...""" or '''...'''. End of lines are automatically included in the string, but it’s possible to prevent this by adding a \ at the end of the line. The following example:

print("""\
Usage: thingy [OPTIONS]
     -h                        Display this usage message
     -H hostname               Hostname to connect to
""")

produces the following output (note that the initial newline is not included):

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Flow
  • 23,572
  • 15
  • 99
  • 156
  • This seems to be functionally identical to [your own answer](https://stackoverflow.com/a/57464608/5349916). Did you mean to edit the original? – MisterMiyagi Feb 24 '23 at 12:55
1

For defining a long string inside a dict, keeping the newlines but omitting the spaces, I ended up defining the string in a constant like this:

LONG_STRING = \
"""
This is a long sting
that contains newlines.
The newlines are important.
"""

my_dict = {
   'foo': 'bar',
   'string': LONG_STRING
}
flix
  • 1,821
  • 18
  • 23
0

I like this approach because it privileges reading. In cases where we have long strings there is no way! Depending on the level of indentation you are in and still limited to 80 characters per line... Well... No need to say anything else

In my view, the Python style guides are still very vague. I took the Eero Aaltonen approach, because it privileges reading and common sense. I understand that style guides should help us and not make our lives a mess.

class ClassName():
    def method_name():
        if condition_0:
            if condition_1:
                if condition_2:
                    some_variable_0 =\
"""
some_js_func_call(
    undefined,
    {
        'some_attr_0': 'value_0',
        'some_attr_1': 'value_1',
        'some_attr_2': '""" + some_variable_1 + """'
    },
    undefined,
    undefined,
    true
)
"""
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Eduardo Lucio
  • 1,771
  • 2
  • 25
  • 43
-12

Generally, I use list and join for multi-line comments/string.

lines = list()
lines.append('SELECT action.enter code here descr as "action", ')
lines.append('role.id as role_id,')
lines.append('role.descr as role')
lines.append('FROM ')
lines.append('public.role_action_def,')
lines.append('public.role,')
lines.append('public.record_def, ')
lines.append('public.action')
query = " ".join(lines)

You can use any string to join all these list elements, like '\n'(newline) or ','(comma) or ' '(space).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
paone
  • 1
  • 1
  • 1
    Why wouldn't you at least use an array literal? – Alexander Oct 25 '18 at 22:11
  • 1
    Arrays are represented by class list. [check out another discussion regarding the array literals](https://stackoverflow.com/questions/1514553/how-to-declare-an-array-in-python) – paone Nov 12 '18 at 06:37
  • I suppose this works, but you should think about performance and readability... – Petro Oct 28 '19 at 12:31