Pythonic way to create a long multi-line string

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP

Pythonic way to create a long multi-line string



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





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





This is "Pythonic way to create multi-line code for a long string" To create a string containing newlines see textwrap.dedent.
– Bob Stein
Jan 29 '15 at 17:16






This is a school example of XY problem. The OP asks: "How to create a multi-line string?", but actually needs to know "How to write an SQL query?". Emphasis should be put on SQL injection.
– cezar
Jan 23 at 10:19






@cezar I wrote this question more than five years ago, but I remember it arose from not knowing how to properly put the long sql query in several lines. I agree I was doing stupid things with that long string, but that was not my question and I wasn't smart enough to look for a better example to illustrate it that didn't include some sql injection concerns.
– Pablo Mescher
Jan 23 at 19:42




18 Answers
18



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.


s



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 veryn long string if I had then 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.





For method 2 and unicode strings: you only have to mark the first string as unicode i.e. u'a'n'b'n'c' => u'abc'.
– Sean
Jul 31 '14 at 14:10





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






@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


+





For reference, here are the official docs to this phenomenon: docs.python.org/2/reference/… (python 2) and docs.python.org/3/reference/… (python 3)
– neverendingqs
Aug 15 '16 at 13:16





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: dev.mysql.com/doc/connector-python/en/…
– Crossfit_and_Beer
Oct 8 '16 at 17:29




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 whitespace a multiline string would contain would be a problem, then this would be a good way to achieve what you want.





@Pablo you can even add comments after the ,
– Ashwini Chaudhary
May 18 '12 at 22:45


,





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 6:16


.format(...)


%





Note that each line must end with a string constant, so ' foo '+variable won't work, but ' foo '+variable+'' will.
– yoyo
Jul 8 '15 at 6:57



' foo '+variable


' foo '+variable+''





Oh man, you have a nasty way of building SQL queries...
– Worker
Aug 28 '15 at 13:14





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': dev.mysql.com/doc/connector-python/en/…
– Crossfit_and_Beer
Oct 8 '16 at 17:30



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"





Thanks. Useful for someone coming from a C background!
– Pavan Manjunath
Jun 23 '14 at 6:38





I would prefer either the triple quote notation or wrapping inside () to the character
– Khanh Hua
Jan 3 '16 at 9:32





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





Great answer. Made my day it really kudos to the interpreter such nuances are build upon from the beginning.
– Doogle
Mar 29 at 8:04



I found myself happy with this one:


string = """This is a
very long string,
containing commas,
that I split up
for readability""".replace('n',' ')





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





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 7:37





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 1 '17 at 12:39



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 parens, join() takes an iterable
"SELECT foo",
"FROM bar",
"WHERE baz",
))



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


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

query == "SELECT fooFROM barWHERE baz" # probably not what you want





+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





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





@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 Addis
Oct 17 '16 at 18:24






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



You can also concatenate variables in when using """ notation:


foo = '1234'

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



EDIT: Found a better way, with named params 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)



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





How would an f-string work if I wanted to log the result of a multi-line string and not have the left-side tabs/spaces shown?
– kuanb
Oct 6 '17 at 20:01



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 condition should be a string, you can do 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'"





This is exactly what I was looking for, a way to combine .format() and multiple string lines.
– wprins
Feb 28 '17 at 2:31



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


?


?





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 at 12:28


cursor.execute(query.format(vars))





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 Ahmad
Apr 2 at 8:31


format





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 4 at 2:15



Your actual code shouldn't work, you are missing whitespaces at the end of "lines" (eg: role.descr as roleFROM...)


role.descr as roleFROM...



There is triplequotes for multiline string:


string = """line
line2
line3"""



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



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.split('n')])





Look into Python's textwrap.dedent function, which is in the standard library, it has the functionality you need.
– bjd2385
Jun 21 at 18:10


textwrap.dedent



You can also place the sql-statement in a seperate file action.sql and load it in the py file with


action.sql


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 formating (like %s or field)



"À la" Scala way (but I think is the most pythonic way as OQ 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:


n


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



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


|



This approach uses just one backslash to avoid an initial linefeed, almost no internal punctuation by using a triple quoted string, strips away local indentation using the textwrap module, and also uses python 3.6 formatted string interpolation ('f') for the account_id and def_id variables. This way looks the most pythonic to me.


account_id


def_id


import textwrap

query = textwrap.dedent(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'''
)



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


textwrap.dedent


def create_snippet():
code_snippet = textwrap.dedent("""
int main(int argc, char* argv)
return 0;

""")
do_something(code_snippet)



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.
http://sqlparse.readthedocs.org/en/latest/api/#sqlparse.format





"recursive function" is not that called lambda?
– erm3nda
Jun 9 '15 at 0:50



Another option that I think is more readable when the code (e.g 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



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. Thanks!


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





OMG, all those nested ifs... give me shivers!
– Victor Schröder
Jan 31 at 9:53


if






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Comments

Popular posts from this blog

Executable numpy error

PySpark count values by condition

Mass disable jenkins jobs