53

This is a question that keeps recurring in all of my programming, python and otherwise. I really like to keep my code under 80 chars if at all possible/not horribly ugly. In a language like Perl, this isn't too hard since white space doesn't matter. In Python, where it does, I wind up knocking my head against the wall more often than I'd like to be trying to think of a "nice" way of splitting up my long lines. So, Code gurus, how do you do it? Any general strategies you can inform me of?

A particular problem I'm dealing with right now is:

self.SomeLongLongName = SomeLongLongName.SomeLongLongName(some_obj, self.user1, self.user2)

When I naturally try to cut this off in Python, the only half decent way available to me seems to be:

self.SomeLongLongName = SomeLongLongName.SomeLongLongName(some_obj,
                                                          self.user1
                                                          self.user2)

It doesn't look that bad, I guess, but it takes up three lines, which is just completely unnecessary. There must be a better way, no?

Note: I know there are those of you who don't like 80 chars a line and have created your own limits. I understand the motivation behind this and respect it, but 80 chars is my preferred limit. Please don't take up space trying to convince me to go over to 120 or some such here.

Paul Fisher
  • 9,618
  • 5
  • 37
  • 53
Eli
  • 36,793
  • 40
  • 144
  • 207
  • 4
    One of the problems may be the fact that your names are so long. Try to think of shorter ways of describing things. – Amber Jan 30 '11 at 05:09
  • 1
    I think my names really wind up long because of the class variables. If I'm calling a function with three class variables, just the "self." portion of those variable names already kills 15 chars. In terms of name shortening in general, I'm really against changing a name to something unintelligible just to save space. A name should be as small as possible while still reasonably describing what it is. – Eli Jan 30 '11 at 05:48
  • 23
    Upvoted to counter @Glenn Maynard's downvote. PEP 8 states clearly, "Limit all lines to a maximum of 79 characters." – johnsyweb Jan 30 '11 at 06:13
  • 6
    @Johnsyweb: And as I said, PEP 8's advice on this is a decade (or more) obsolete, and results in terrible, unreadable code. It's bad advice and should be ignored. Also, upvoting to "counter a downvote" rather than because you *actually think a question deserves an upvote* entirely misses the point of a voting mechanism (not that voting on this site is meaningful to begin with). – Glenn Maynard Jan 30 '11 at 06:44
  • @Eli - If your names need to be that long, you're doing too much describing IMHO. Shorter != less clear. – Chris Lutz Jan 30 '11 at 07:09
  • 2
    @Glenn: I think it's a worthwhile question, so mu upvote stands. The fact that it counters yours is a plus (no pun intended). If PEP8 is obsolete, can you please point me to its successor? – johnsyweb Jan 30 '11 at 07:28
  • 11
    @Glenn Maynard: Human brains are no more advanced at reading long lines today as they were a decade ago. Python can do many things in 80 characters (I would use 120 limit in Java). – jfs Jan 30 '11 at 09:54
  • 4
    @Sebastian: I have no trouble at all reading code with line lengths of 100-120 characters. Don't confuse code wrapping with paragraph wrapping, where *every line* is at or near its maximum length. – Glenn Maynard Jan 30 '11 at 10:33
  • 4
    @Glenn Maynard: There is another practical reason for keeping lines short. It allows me to view two files side-by-side on the screen without cranking the font size way down. Yes, there's a trade-off in elegance, but this is another reason why some of us want to stick to 80. – monotasker Aug 16 '12 at 15:47
  • 1
    @monotasker: Even at my fairly large font size I could fit two files at 110 columns--far more sane than 80. In any case, you can obfuscate your code if you like, but official recommendations of code obfuscation are perverse. – Glenn Maynard Aug 16 '12 at 18:46

7 Answers7

36

Your code style seems to insist that if you break a line inside a parenthesis, lines below need to line up with it:

self.SomeLongLongName = SomeLongLongName.SomeLongLongName(some_obj,
                                                          self.user1
                                                          self.user2)

If you are willing to drop this requirement, you can format the code as follows, where continued lines have a fixed double indent:

self.SomeLongLongName = SomeLongLongName.SomeLongLongName(
        some_obj, self.user1, self.user2)

This avoids writing code down the right-hand margin on the page, and is very readable once you are used to it. It also has the benefit that if you modify the name of "SomeLongLongName", you don't have to re-indent all of the following lines. A longer example would be as follows:

if SomeLongLongName.SomeLongLongName(
        some_obj, self.user1, self.user2):
    foo()
else:     
    bar()

The double indent for continued lines allows you to visually separate them from lines indented because they are in an if or else block.

As others have noted, using shorted names also helps, but this isn't always possible (such as when using an external API).

davidg
  • 5,868
  • 2
  • 33
  • 51
  • 2
    Yes. I do this in all languages: C, Python, whatever. – steveha Jan 30 '11 at 07:06
  • Nice! I had no idea that worked! Under what circumstances does it work? – Eli Jan 30 '11 at 18:07
  • 4
    When you have a continued line (either because a parenthesis is still open, or a backslash character was on the previous line, etc.), python will ignore the indentation on it. This means that you are free to indent continued lines as you wish. – davidg Jan 30 '11 at 22:44
  • 1
    I don't know why, but this makes me cringe. I think the first example (stacked up along the right) is much more obvious. I recognize that as a function call before my eyes really even focus on it. The latter looks like a syntax error until I focus on it. I find that distracting. – Mark E. Haase Dec 16 '12 at 16:33
22
self.SomeLongLongName = SomeLongLongName.\
    SomeLongLongName(some_obj, self.user1, self.user2)

'\' is your friend. Of course, you already know that you can split lines in an argument list at commas, without using '\'. Also, if you have long strings:

myLongString = "This is a really long string that is going to be longer than 80 characters so oh my what do I do to make this work out?"

becomes:

myLongString = "This is a really long string that is going to be longer than"\
    " 80 characters so oh my what do I do to make this work out?"

This works because Python will combine adjacent string literals, ignoring whitespace between the adjacent literal strings.

Michael Kent
  • 1,736
  • 12
  • 11
  • 4
    I didn't believe you when you said Python concatenates adjacent string literals, so I went and tested it. It really does! Does Python actually treat multiple consecutive string literals as a single string for syntactical purposes? – Ryan C. Thompson Jan 30 '11 at 05:10
  • 1
    @Ryan: [Yes](http://docs.python.org/reference/lexical_analysis.html#string-literal-concatenation). – ephemient Jan 30 '11 at 05:40
  • 1
    @Ryan Thompson: Yes. This was borrowed from C. – John Machin Jan 30 '11 at 06:16
  • 1
    One gotcha with \ line continuation is that the \ must not have any whitespace after it or it won't work! Yes, that's right, Python also has significant *trailing* whitespace :) – Scott Griffiths Jan 30 '11 at 12:59
  • @Scott: It's the same in C preprocessor directives though ;) –  Jan 30 '11 at 13:58
  • 5
    Parentheses could be used for strings: `("abc" \n "def")` – jfs Jan 30 '11 at 17:05
22

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. Make sure to indent the continued line appropriately. The preferred place to break around a binary operator is after the operator, not before it.

PEP 8 Style Guide for Python Code (follow link for examples).

johnsyweb
  • 136,902
  • 23
  • 188
  • 247
  • 11
    PEP8 itself has a brilliant example of why such a short column width is so broken. Its "Rectangle" class is unreadable to the point of being a self-parody, which makes it perplexing that people actually take it seriously. Don't write code like that. – Glenn Maynard Jan 30 '11 at 06:49
  • 6
    Agreed: the `Rectangle` class is a terrible example, but it highlights *how* to break lines. However, PEP8 is the definitive style guide for Python code. If you're going to write Python code, you should stick to it. [Much like if you're going to write Perl code you should avoid meaningful variable names ;-)] – johnsyweb Jan 30 '11 at 07:23
  • 7
    No style guide is "definitive"; they're guides, not rulebooks, and can only be applied usefully when mixed with a strong dose of common sense. That's lacking, I think, when continuing to wrap lines as if 80x25 terminals are still a typical development environment. – Glenn Maynard Jan 30 '11 at 08:46
  • @GlennMaynard I am actually with Glenn on this one. 80 character column width is too little. PEP8 needs to be revised or its successor should be written. – Ankur Agarwal Jul 07 '15 at 23:07
  • New PEP8 (link by @Johnsyweb) prefers breaking binary operators *before* the operator (while technically permitting both ways). – amka66 Feb 06 '21 at 17:51
6

Some people were citing the Rectangle class as a poor example. This example in the pep8 is not the only way to do this.

Original:

class Rectangle(Blob):

    def __init__(self, width, height,
                 color='black', emphasis=None, highlight=0):
        if (width == 0 and height == 0 and
            color == 'red' and emphasis == 'strong' or
            highlight > 100):
            raise ValueError("sorry, you lose")
        if width == 0 and height == 0 and (color == 'red' or
                                           emphasis is None):
            raise ValueError("I don't think so -- values are %s, %s" %
                             (width, height))
        Blob.__init__(self, width, height,
                      color, emphasis, highlight)

This is how I would write it.

class Rectangle(Blob):

    def __init__(self, width, height, color='black', emphasis=None,
            highlight=0):
        if (width == 0 and height == 0 and color == 'red' and
                emphasis == 'strong' or highlight > 100):
            raise ValueError("sorry, you lose")
        if width == 0 and height == 0 and (color == 'red' or 
                emphasis is None):
            msg = "I don't think so -- values are %s, %s" % (width, height)     
            raise ValueError(msg)
        Blob.__init__(self, width, height, color, emphasis, highlight)

The reason being is:

  • Additional indentation to line up with '(' is a waste of time if your editor isn't doing it for you and harder to read since there is so much leading white space IMO.
  • I try to break as late as possible unless there is a compelling reason in the code logic.
  • Lining up with the '(' in this case created the exact same indentation level as the next line... very bad coincidence! Double indenting continuation lines solves this problem.
  • I prefer avoidance if the reason for having to use line continuation is trying to do too much on one line. The example here is the ValueError where they are formatting using the string format operator. I set msg instead. (Note: Format Strings using the format method are preferred, and % is deprecated since 3.1).
Derek Litz
  • 10,529
  • 7
  • 43
  • 53
3

Try shortening your names if you have that option. Otherwise you can use the \ character to continue your lines onto the next line (along with other similar constructs such as what you mentioned up above).

Noctis Skytower
  • 21,433
  • 16
  • 79
  • 117
3

I second Michael Kent's answer (and I upvoted it).

But also, you should read "PEP 8" and absorb its lessons.

http://www.python.org/dev/peps/pep-0008/

But Python, with its namespaces, powerful features, and object-oriented classes, should let you use conveniently short names for things.

In C, you need to use long identifiers in many cases because names need to be unique within a given scope. Thus:

char *StringFromInt(int x);
char *StringFromFloat(float x);
char *StringFromUnsigned(unsigned int x);

char *str_temp = strdup(StringFromUnsigned(foo_flags));

In Python, all of these would be the builtin str():

temp = str(foo_flags)

In C++ you have classes and name spaces, so you should be able to use object-oriented features as in Python, but in C you need globally unique names, so you often have to do stuff like this:

typedef struct s_foo
{
   // struct members go here
} FOO;

FooAdd();
FooSubtract();
StringFromFoo();

In Python, you should either add member functions, or overload operators, as appropriate:

class Foo(object):
    def __init__(self):
        # member variables initialized here
    def add(self, x):
        # add x to a Foo
    def subtract(self, x):
        # subtract x from a Foo
    def __str___(self):
        # return a string that represents a foo

f = Foo()
f.add(x)
f.sub(y)
# the following two both use __str__()
temp = str(f)
print(f)

You may also favor really long variable names for self-documenting purposes. I prefer terseness:

import math

class Circle(object):
    """\
Circle: a class representing a circle in a plane.
Includes the following member functions:
    area() -- return the area of the circle"""
    def __init__(self, center=Point([0, 0]), radius=0.0):
        """\
Circle(center, radius)
center must be an instance of class Point() or convertible to Point()
radius must be an int or float and must not be negative"""
        if radius < 0:
            raise ValueError("radius must be >= 0")
        self.center = Point(center)
        self.radius = float(radius)
    def area(self):
        "returns area as a float."
         return math.pi * self.radius ** 2

c = Circle([23, 45], 0.5)
print(c.area())


class CircleGraphicsObject(object):
    def __init__(self, CenterOfTheCircle, RadiusOfTheCircle):
        # init code goes here
    def AreaOfTheCircle(self):
        return math.pi * self.RadiusOfTheCircle ** 2

CircleInstance = CircleGraphicsObject(PointObject([23, 45]), 0.5)
print(CircleInstance.AreaOfTheCircle())

I strongly prefer the first, terse style to the second. As per PEP 8, I like all-lower-case variable names (such as c for the Circle instance). In Python, it is also generally recommended to use "Duck Typing" like I did in the terse class: if you want the radius to be a float, then coerce it to a float in __init__() rather than checking its type. Likewise, rather than checking to see if you were passed a Point instance, just coerce whatever you get to a Point. You are letting Point.__init__() raise an exception if the argument makes no sense as a Point; there is no need for an extra check in Circle.__init__(). Also, your Point.__init__() function can explicitly check to see if you passed it an instance of Point and return the instance unchanged, if it is really expensive to init a Point. (In this example, a Point is really just a pair of values, so it's probably fast enough to just re-create the point and you don't need the check.)

You might notice the odd way I did the multi-line triple-quoted string. Because of the indenting rules in Python, I needed to indent the triple-quoted string, but I don't want to indent the lines of the string because the indent would be part of the string. Really I want all of the multiple lines to be at the left margin, so I can clearly see how long those lines are getting (and make sure they are all 79 chars or shorter). So I use the backslash escape to allow the first line of the multi-line string to be at the left margin with the other lines, without inserting a newline at the beginning of the multi-line string.

Anyway, the terser style means your variable names and such are easier to type, and it is easier to fit your lines in the 79-column limit recommended by PEP 8.

It wouldn't even be completely horrible to use internal member names that are one letter long, in a class as simple as this. With only two members, you could pretty well use .c for the center member and .r for the radius. But that doesn't scale up well, and .center and .radius are still easy to type and easy to remember.

It's also a very good idea to put informative docstrings. You can use somewhat terse names, but have longer explanations in the docstring.

class Foo(object):
    # init goes here
    def area(self):
        "returns area as a float."
         return self.area

class VerboseFoo(object):
    # init goes here
    def AreaAsFloat(self):
        return self.FloatAreaValue

Namespaces are great. Notice how clear it is when we use math.pi; you know it is the math constant, and you could have some local variable pi (for "Program Index" perhaps) and it does not collide with the math constant.

steveha
  • 74,789
  • 21
  • 92
  • 117
2

I find myself using more and more intermediate variables, that not only help stay within 80 characters, but make the code more readable by giving things descriptive names like:

old_name = 'reallylonguglypath/to/current/file.foo'
new_name = 'evenmoreuglylong/to/new/desination/for/file.foo' 
os.rename(old_name, new_name)

rather than:

os.rename("reallylonguglypath/to/current/file.foo",
              "evenmoreuglylong/to/new/desination/for/file.foo")

You can do this with long module and class names too

method = SomeLongClassName.SomeLongMethodName
self.SomeLongLongName = method(some_obj, self.user1, self.user2)
crizCraig
  • 8,487
  • 6
  • 54
  • 53