231

How would you go about formatting a long line such as this? I'd like to get it to no more than 80 characters wide:

logger.info("Skipping {0} because its thumbnail was already in our system as {1}.".format(line[indexes['url']], video.title))

Is this my best option?

url = "Skipping {0} because its thumbnail was already in our system as {1}."
logger.info(url.format(line[indexes['url']], video.title))
Gattster
  • 4,613
  • 5
  • 27
  • 39

6 Answers6

427

That's a start. It's not a bad practice to define your longer strings outside of the code that uses them. It's a way to separate data and behavior. Your first option is to join string literals together implicitly by making them adjacent to one another:

("This is the first line of my text, "
"which will be joined to a second.")

Or with line ending continuations, which is a little more fragile, as this works:

"This is the first line of my text, " \
"which will be joined to a second."

But this doesn't:

"This is the first line of my text, " \ 
"which will be joined to a second."

See the difference? No? Well you won't when it's your code either.

(There's a space after \ in the second example.)

The downside to implicit joining is that it only works with string literals, not with strings taken from variables, so things can get a little more hairy when you refactor. Also, you can only interpolate formatting on the combined string as a whole.

Alternatively, you can join explicitly using the concatenation operator (+):

("This is the first line of my text, " + 
"which will be joined to a second.")

Explicit is better than implicit, as the zen of python says, but this creates three strings instead of one, and uses twice as much memory: there are the two you have written, plus one which is the two of them joined together, so you have to know when to ignore the zen. The upside is you can apply formatting to any of the substrings separately on each line, or to the whole lot from outside the parentheses.

Finally, you can use triple-quoted strings:

"""This is the first line of my text
which will be joined to a second."""

This is often my favorite, though its behavior is slightly different as the newline and any leading whitespace on subsequent lines will show up in your final string. You can eliminate the newline with an escaping backslash.

"""This is the first line of my text \
which will be joined to a second."""

This has the same problem as the same technique above, in that correct code only differs from incorrect code by invisible whitespace.

Which one is "best" depends on your particular situation, but the answer is not simply aesthetic, but one of subtly different behaviors.

Iulian Onofrei
  • 9,188
  • 10
  • 67
  • 113
jcdyer
  • 18,616
  • 5
  • 42
  • 49
  • 30
    The CPython compiler optimizes out literal operations as much as possible, which means that adding two string literals results in only a single string literal in the bytecode. – Ignacio Vazquez-Abrams Jan 13 '10 at 18:03
  • 2
    While all of the answers I've received are helpful, yours definitely helps me understand all of the ways to break strings up. Was the problem with the "\" line ending that there was a space after it? – Gattster Jan 13 '10 at 18:05
  • 1
    I can't see the difference here, but then, that's mostly because of SO's rather primitive syntax coloring. (Some perfectly good code is virtually unreadable on SO, but only because it's not in a language whose syntax is very close to C.) It's not unusual to make your editor obnoxiously highlight trailing spaces, since they're rarely useful (or intentional). :-) – Ken Jan 13 '10 at 18:13
  • @Gattster -- Yup. You caught it. It shows up when you select the text. And yeah, good text editors/IDEs can help with that. – jcdyer Jan 13 '10 at 20:22
  • I've fallen into that \(white_space) tramp once. Horrible experience. – Zen Jun 20 '14 at 04:15
  • doesn't work if text itself contains quotes. for example `` – Khurshid Alam Apr 23 '17 at 08:11
  • 1
    @KhurshidAlam you could use single quotes `'` to contain that string, or escape the double quotes inside your string, or use the triple double quotes `"""`. The problem with quoted strings containing quotes is the same whether you use a single line or multiple lines to define the literal string. – hugovdberg Jun 27 '18 at 09:19
  • 1
    My editor removes trailing whitespace always. I recommend you enable the same setting. Of course then the whitespace on the new line is still part of the string, so I ended up using `+`. – ThaJay Oct 18 '19 at 11:41
58

Consecutive string literals are joined by the compiler, and parenthesized expressions are considered to be a single line of code:

logger.info("Skipping {0} because it's thumbnail was "
  "already in our system as {1}.".format(line[indexes['url']],
  video.title))
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
15

Personally I dislike hanging open blocks, so I'd format it as:

logger.info(
    'Skipping {0} because its thumbnail was already in our system as {1}.'
    .format(line[indexes['url']], video.title)
)

In general I wouldn't bother struggle too hard to make code fit exactly within a 80-column line. It's worth keeping line length down to reasonable levels, but the hard 80 limit is a thing of the past.

bobince
  • 528,062
  • 107
  • 651
  • 834
  • 11
    It's not really a thing of the past. The Python standard library still uses PEP8 as its style guide, so the rule still exists, and plenty of people (myself included) follow it. It's a convenient place to draw the line. – Devin Jeanpierre Jan 13 '10 at 18:42
  • 3
    I wonder how many projects still follow the 80 char rule. For the average window size I use, I think 100-120 is more productive for me than 80 chars. – Gattster Jan 14 '10 at 05:59
  • 1
    Yes, that's about the line length I use too, though [horror! sacrilege!] I use a proportional font, so exact line length isn't so critical. It's more a case of how much logic on a single line is readable than how many characters, as such... if I've got a long string of data that no-one needs to read I'm happy to let it spill over 120. – bobince Jan 14 '10 at 12:41
  • Proportional fonts for code - I'm with you, brother. Judging by the distaste everyone I've ever worked with have had for them though, the world ain't ready. – jlarcombe Jan 19 '10 at 11:03
  • @bobince: why do you use a proportional font? What are the advantages? – Greg Oct 17 '12 at 14:45
  • @Greg: same as why you'd use proportional fonts for any other kind of text: readability. Naturally you need to pick a font that has good characteristics like 1/l/O/0 distinction, but then that's true of monospaced fonts too. – bobince Oct 18 '12 at 07:56
  • 4
    ~80 characters also make it easier to diff 2 files side-by-side on the same screen. Also, if your debugging something during a dire emergency on the console of a server you'll really appreciate the 80 character limit! :) – Mick T Oct 06 '15 at 19:35
  • If I'm resolving merge conflicts, those 80 characters quickly turn into 240 characters lines (+ scroll bars, + line numbers, + diff markers). Even if I had the screen space to extend it to 300 characters or more, it makes the windows really huge. – Hubert Kario May 15 '17 at 14:47
  • FWIW the first line of your paragraph in my browser is "In general I wouldn't bother struggle too hard to make code fit exactly within a 80-column line. It's". That's 103 characters. – Martin Jambon Jun 04 '18 at 18:04
11

You can use textwrap module to break it in multiple lines

import textwrap
str="ABCDEFGHIJKLIMNO"
print("\n".join(textwrap.wrap(str,8)))

ABCDEFGH
IJKLIMNO

From the documentation:

textwrap.wrap(text[, width[, ...]])
Wraps the single paragraph in text (a string) so every line is at most width characters long. Returns a list of output lines, without final newlines.

Optional keyword arguments correspond to the instance attributes of TextWrapper, documented below. width defaults to 70.

See the TextWrapper.wrap() method for additional details on how wrap() behaves.

Saurabh
  • 7,525
  • 4
  • 45
  • 46
4

For anyone who is also trying to call .format() on a long string, and is unable to use some of the most popular string wrapping techniques without breaking the subsequent .format( call, you can do str.format("", 1, 2) instead of "".format(1, 2). This lets you break the string with whatever technique you like. For example:

logger.info("Skipping {0} because its thumbnail was already in our system as {1}.".format(line[indexes['url']], video.title))

can be

logger.info(str.format(("Skipping {0} because its thumbnail was already"
+ "in our system as {1}"), line[indexes['url']], video.title))

Otherwise, the only possibility is using line ending continuations, which I personally am not a fan of.

Simon Alford
  • 2,405
  • 1
  • 12
  • 10
1

Solution without extra packages load:

def split_by_len(txt: str, l: int, sep: str or None='\n') -> str or list:
    """
    txt: str text
    l: split length (symbols per split)
    sep: separate string or None for list of strs
    """
    spl_list = [txt[i * l : i * l + l] for i in range(len(txt) // l + 1)]
    return spl_list if sep==None else sep.join(spl_list)

Example 1:

print(split_by_len(txt='XXXXX', l=2, sep='\n'))

XX
XX
X

Example 2:

print(split_by_len(txt='XXXXX', l=2, sep=' '))

XX XX X

Example 3:

print(split_by_len(txt='XXXXX', l=2, sep=None))

['XX', 'XX', 'X']
George Shimanovsky
  • 1,668
  • 1
  • 17
  • 15