In defence of 80-char lines

Discussion in 'Python' started by Steven D'Aprano, Apr 4, 2013.

  1. Steven D'Aprano, Apr 4, 2013
    #1
    1. Advertising

  2. Steven D'Aprano

    Andrew Berg Guest

    While I agree that not having a line take up hundreds of characters is a
    good thing, 80 is really arbitrary in 2013 and having any self-imposed
    hard limit is silly. When you put a single 4- or 5-character word on a
    new line because you don't want to go over 80 (or 120 or whatever), the
    code is /less/ readable. A better guideline is to make new lines as
    necessary to make things more readable rather than blindly stick to some
    hard limit and say it's more readable just because.

    Also, IMO, 80 is far too limiting and I find 120-130 much better. Then
    again, I like small font sizes and avoid lower resolution screens like
    the plague.
    --
    CPython 3.3.0 | Windows NT 6.2.9200 / FreeBSD 9.1
    Andrew Berg, Apr 4, 2013
    #2
    1. Advertising

  3. On 04/03/2013 09:59 PM, Andrew Berg wrote:
    > While I agree that not having a line take up hundreds of characters is a
    > good thing, 80 is really arbitrary in 2013 and having any self-imposed
    > hard limit is silly. When you put a single 4- or 5-character word on a
    > new line because you don't want to go over 80 (or 120 or whatever), the
    > code is /less/ readable. A better guideline is to make new lines as
    > necessary to make things more readable rather than blindly stick to some
    > hard limit and say it's more readable just because.
    >
    > Also, IMO, 80 is far too limiting and I find 120-130 much better. Then
    > again, I like small font sizes and avoid lower resolution screens like
    > the plague.



    I have to agree. To some degree, it's a matter of taste: for me, 80c
    limit looks ugly to the extreme, at least in Django; but 140+ looks even
    uglier, and the longer line is, the uglier it looks. The optimal size
    for Django code is a 105 char soft limit -- by soft limit I mean that
    under 105 it's always one line, 105-110 I decide on a case-by-case basis
    and over 110 is always split.

    So my preference is: 105 > 120-130 > 140 > 80 > 140+

    The trade-off is that on one hand, the code is more readable when a
    single line is a single "operation", from a cognitive standpoint, when
    you're thinking about the logic of the function as a whole, or a subset
    of a function if it's too long (which it shouldn't be, right?) On the
    other hand, even if your monitor is wide, you probably still want to fit
    in the browser window and the terminal window, and as the blog author
    rightly notes, really long lines do get harder to read.

    Again, I mostly work with Django and I suspect if I worked in regular
    Python I would possibly gravitate towards 95-100 limit.

    I find the blog author's point about fitting more text nonsensical: you
    can obviously fit more text PER LINE if lines are longer! And you can
    quite easily fit two 120-130 wide gvim screens on a modern monitor with
    room to spare.

    I'm sure eyesight acuity also figures into this: I prefer to work
    without glasses -- otherwise my eyes get tired after a couple of hours;
    but this means I can't see code on my second monitor. If I could, I
    might have preferred having browser and terminal on one monitor and Gvim
    with slightly longer width limits than I use now.

    -m


    --
    Lark's Tongue Guide to Python: http://lightbird.net/larks/

    The Bible is literature, not dogma. George Santayana
    Mitya Sirenef, Apr 4, 2013
    #3
  4. Steven D'Aprano

    llanitedave Guest

    I also tend to prefer a maximum between 110 and 120 characters. I find continuation lines confusing, and when you use some third-party tools, such as wxPython, for example, the boilerplate code leads to some long lines.

    I would hate to have to break up this line, for instance:

    self.mainLabel.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = "FreeSans"))

    Especially if it's already indented a few levels to begin with.

    With most of your code in classes, you already got most of it indented two levels right off the bat.
    llanitedave, Apr 4, 2013
    #4
  5. Steven D'Aprano

    rusi Guest

    On Apr 4, 6:36?am, Steven D'Aprano <steve
    > wrote:
    > Although PEP 8 is only compulsory for the Python standard library, many
    > users like to stick to PEP 8 for external projects.
    >
    > http://www.python.org/dev/peps/pep-0008/
    >
    > http://blog.languager.org/2012/10/layout-imperative-in-functional.htmlithperhaps one glaring exception: many people hate, or ignore, PEP 8's
    > recommendation to limit lines to 80 characters. (Strictly speaking, 79
    > characters.)
    >
    > Here is a good defence of 80 char lines:
    >
    > http://wrongsideofmemphis.com/2013/03/25/80-chars-per-line-is-great/


    The exchange on hacker news linked from there makes for a nice read --
    tnx.

    I had a blog article http://blog.languager.org/2012/10/layout-imperative-in-functional.html
    on this subject. It started from a python discussion, though its more
    relevant to Haskell.
    What does not so easily come out there is that the wide-line code
    samples I posted which read ok to me were not to some readers. So I
    moved it to gist, but even there some would get the horizontal scroll
    bar. Reading it 'raw' seems to remove the problem -- though I can
    hardly promise that for all devices. So from this POV the point that
    was made was opposite to the one I was trying to make =)

    The discussion that followed on haskell cafe
    http://www.haskell.org/pipermail/haskell-cafe/2012-October/104224.html
    made a number of interesting points about pros and cons of long lines.
    rusi, Apr 4, 2013
    #5
  6. On Wed, 03 Apr 2013 21:32:33 -0700, llanitedave wrote:

    > I also tend to prefer a maximum between 110 and 120 characters. I find
    > continuation lines confusing, and when you use some third-party tools,
    > such as wxPython, for example, the boilerplate code leads to some long
    > lines.


    Excessive boilerplate, and long lines, is a code-smell that suggests
    strongly that the code needs refactoring and/or simplifying.


    > I would hate to have to break up this line, for instance:
    >
    > self.mainLabel.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD,
    > faceName = "FreeSans"))



    Here, let me do that for you, with two, no, three, no FOUR levels of
    indentation :)


    self.mainLabel.SetFont(self.label_format)


    Now when you want to change the font of your labels, you can change them
    all with *one* edit. Or you can add themes to your application by reading
    style info from a config file. Even if you don't want to do that, you
    still have the benefit of much more readable code.

    Clearly you have to define the label format in the class. Here's one
    simple way:

    class MyClass(whatever):
    label_format = wx.Font(
    12, wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName="FreeSans")

    def __init__(self, label_format=None):
    if label_format is not None:
    # Over-ride the default.
    self.label_format = label_format


    Even if you don't want to do that, you can still fit it into 80 char
    lines:

    # 80 characters, not 79. Oh well.
    font = wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName="FreeSans")
    self.mainLabel.SetFont(font)


    And finally, when all is said and done, the most important rule from PEP 8
    applies: know when to break the rules.



    --
    Steven
    Steven D'Aprano, Apr 4, 2013
    #6
  7. Steven D'Aprano

    gregor Guest

    Am Wed, 3 Apr 2013 21:32:33 -0700 (PDT)
    schrieb llanitedave <>:

    > I would hate to have to break up this line, for instance:
    >
    > self.mainLabel.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD,
    > faceName = "FreeSans"))


    I think this is much more readable:

    self.mainLabel.SetFont(wx.Font(12,
    wx.DEFAULT,
    wx.NORMAL,
    wx.BOLD,
    faceName = "FreeSans"))

    Emacs for example does this indentation with the TAB key automatically.

    --
    Greg
    gregor, Apr 4, 2013
    #7
  8. Steven D'Aprano

    Peter Otten Guest

    llanitedave wrote:

    > I also tend to prefer a maximum between 110 and 120 characters. I find
    > continuation lines confusing, and when you use some third-party tools,
    > such as wxPython, for example, the boilerplate code leads to some long
    > lines.
    >
    > I would hate to have to break up this line, for instance:
    >
    > self.mainLabel.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD,
    > faceName = "FreeSans"))


    I'm not a wx user, but I think I would prefer

    labelfont = wx.Font(
    pointSize=12,
    style=wx.DEFAULT,
    family=wx.NORMAL,
    weight=wx.BOLD,
    faceName="FreeSans")
    self.mainLabel.SetFont(labelfont)

    even if I knew the order of the arguments and the meaning of constants like
    DEFAULT and NORMAL by heart.
    Peter Otten, Apr 4, 2013
    #8
  9. Steven D'Aprano

    Rui Maciel Guest

    Steven D'Aprano wrote:

    > Although PEP 8 is only compulsory for the Python standard library, many
    > users like to stick to PEP 8 for external projects.
    >
    > http://www.python.org/dev/peps/pep-0008/
    >
    > With perhaps one glaring exception: many people hate, or ignore, PEP 8's
    > recommendation to limit lines to 80 characters. (Strictly speaking, 79
    > characters.)
    >
    >
    > Here is a good defence of 80 char lines:
    >
    > http://wrongsideofmemphis.com/2013/03/25/80-chars-per-line-is-great/



    The now arbitrary 80-column limit is a remnant of the limitations built into
    ancient terminals.

    Why not let the text editor auto-wrap the lines? They can do that now.


    Rui Maciel
    Rui Maciel, Apr 4, 2013
    #9
  10. Steven D'Aprano

    Tim Chase Guest

    On 2013-04-04 08:43, Peter Otten wrote:
    > llanitedave wrote:
    >> self.mainLabel.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = "FreeSans"))

    >
    > I think I would prefer
    >
    > labelfont = wx.Font(
    > pointSize=12,
    > style=wx.DEFAULT,
    > family=wx.NORMAL,
    > weight=wx.BOLD,
    > faceName="FreeSans")
    > self.mainLabel.SetFont(labelfont)


    +1
    The only change I'd make to this suggestion would be to add a
    semi-superfluous comma+newline after the last keyword argument too:

    labelfont = wx.Font(
    pointSize=12,
    style=wx.DEFAULT,
    family=wx.NORMAL,
    weight=wx.BOLD,
    faceName="FreeSans",
    )

    which makes diffs cleaner when you need to insert something after
    faceName:

    --- peter1.txt 2013-04-04 06:03:01.420762566 -0500
    +++ peter2.txt 2013-04-04 06:03:34.736762582 -0500
    @@ -3,4 +3,5 @@
    style=wx.DEFAULT,
    family=wx.NORMAL,
    weight=wx.BOLD,
    - faceName="FreeSans")
    + faceName="FreeSans",
    + otherValue=42)

    vs.

    --- tkc1.txt 2013-04-04 06:02:52.436762562 -0500
    +++ tkc2.txt 2013-04-04 06:03:51.392762588 -0500
    @@ -4,4 +4,5 @@
    family=wx.NORMAL,
    weight=wx.BOLD,
    faceName="FreeSans",
    + otherValue=42,
    )

    Additionally, if there are lots of keyword parameters like this, I'd
    be tempted to keep them in sorted order for ease of tracking them
    down (though CSS has long-standing arguments on how properties should
    be ordered, so to each their own on this).

    -tkc
    Tim Chase, Apr 4, 2013
    #10
  11. Steven D'Aprano

    Roy Smith Guest

    In article <>,
    llanitedave <> wrote:

    > I would hate to have to break up this line, for instance:
    >
    > self.mainLabel.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName =
    > "FreeSans"))


    I would write that as some variation on

    self.mainLabel.SetFont(wx.Font(12,
    wx.DEFAULT,
    wx.NORMAL,
    wx.BOLD,
    faceName="FreeSans"))

    This lets the reader see at a glance that all the arguments go with
    wx.Font(), not with SetFont(), without having to visually parse and
    match parenthesis levels.

    Actually, I would probably break it up further as:

    my_font = wx.Font(12,
    wx.DEFAULT,
    wx.NORMAL,
    wx.BOLD,
    faceName="FreeSans")
    self.mainLabel.SetFont(my_font)

    The last thing on my mind when deciding how to format this is whether I
    would be able to punch it onto a single card.
    Roy Smith, Apr 4, 2013
    #11
  12. Steven D'Aprano

    Jason Swails Guest

    On Thu, Apr 4, 2013 at 7:09 AM, Tim Chase <>wrote:

    > On 2013-04-04 08:43, Peter Otten wrote:
    > > llanitedave wrote:
    > >> self.mainLabel.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD,

    > faceName = "FreeSans"))
    > >
    > > I think I would prefer
    > >
    > > labelfont = wx.Font(
    > > pointSize=12,
    > > style=wx.DEFAULT,
    > > family=wx.NORMAL,
    > > weight=wx.BOLD,
    > > faceName="FreeSans")
    > > self.mainLabel.SetFont(labelfont)

    >
    > +1
    > The only change I'd make to this suggestion would be to add a
    > semi-superfluous comma+newline after the last keyword argument too:
    >
    > labelfont = wx.Font(
    > pointSize=12,
    > style=wx.DEFAULT,
    > family=wx.NORMAL,
    > weight=wx.BOLD,
    > faceName="FreeSans",
    > )
    >
    > which makes diffs cleaner when you need to insert something after
    > faceName:
    >
    > --- peter1.txt 2013-04-04 06:03:01.420762566 -0500
    > +++ peter2.txt 2013-04-04 06:03:34.736762582 -0500
    > @@ -3,4 +3,5 @@
    > style=wx.DEFAULT,
    > family=wx.NORMAL,
    > weight=wx.BOLD,
    > - faceName="FreeSans")
    > + faceName="FreeSans",
    > + otherValue=42)
    >
    > vs.
    >
    > --- tkc1.txt 2013-04-04 06:02:52.436762562 -0500
    > +++ tkc2.txt 2013-04-04 06:03:51.392762588 -0500
    > @@ -4,4 +4,5 @@
    > family=wx.NORMAL,
    > weight=wx.BOLD,
    > faceName="FreeSans",
    > + otherValue=42,
    > )
    >


    +1

    I wasn't aware you could do this (superfluous trailing commas), although I
    admit it hadn't occurred to me to try. I use git for virtually everything,
    and I regularly parse diffstats -- this would make them much easier to
    grok. (It's an incredibly helpful bug-tracking technique)

    Thanks!
    Jason
    Jason Swails, Apr 4, 2013
    #12
  13. Steven D'Aprano

    Roy Smith Guest

    In article <>,
    Jason Swails <> wrote:

    > The only time I regularly break my rule is for regular expressions (at some
    > point I may embrace re.X to allow me to break those up, too).


    re.X is a pretty cool tool for making huge regexes readable. But, it
    turns out that python's auto-continuation and string literal
    concatenation rules are enough to let you get much the same effect.
    Here's a regex we use to parse haproxy log files. This would be utter
    line noise all run together. This way, it's almost readable :)

    pattern = re.compile(r'haproxy\[(?P<pid>\d+)]: '
    r'(?P<client_ip>(\d{1,3}\.){3}\d{1,3}):'
    r'(?P<client_port>\d{1,5}) '

    r'\[(?P<accept_date>\d{2}/\w{3}/\d{4}:)\d{2}){3}\.\d{3})] '
    r'(?P<frontend_name>\S+) '
    r'(?P<backend_name>\S+)/'
    r'(?P<server_name>\S+) '
    r'(?P<Tq>(-1|\d+))/'
    r'(?P<Tw>(-1|\d+))/'
    r'(?P<Tc>(-1|\d+))/'
    r'(?P<Tr>(-1|\d+))/'
    r'(?P<Tt>\+?\d+) '
    r'(?P<status_code>\d{3}) '
    r'(?P<bytes_read>\d+) '
    r'(?P<captured_request_cookie>\S+) '
    r'(?P<captured_response_cookie>\S+) '
    r'(?P<termination_state>[\w-]{4}) '
    r'(?P<actconn>\d+)/'
    r'(?P<feconn>\d+)/'
    r'(?P<beconn>\d+)/'
    r'(?P<srv_conn>\d+)/'
    r'(?P<retries>\d+) '
    r'(?P<srv_queue>\d+)/'
    r'(?P<backend_queue>\d+) '
    r'(\{(?P<request_id>.*?)\} )?'
    r'(\{(?P<captured_request_headers>.*?)\} )?'
    r'(\{(?P<captured_response_headers>.*?)\} )?'
    r'"(?P<http_request>.+)"'
    )

    And, for those of you who go running in the other direction every time
    regex is suggested as a solution, I challenge you to come up with easier
    to read (or write) code for parsing a line like this (probably
    hopelessly mangled by the time you read it):

    2013-04-03T00:00:00+00:00 localhost haproxy[5199]: 10.159.19.244:57291
    [02/Apr/2013:23:59:59.811] app-nodes next-song-nodes/web8.songza.com
    0/0/3/214/219 200 593 sessionid=NWiX5KGOdvg6dSaA
    sessionid=NWiX5KGOdvg6dSaA ---- 249/249/149/14/0 0/0
    {4C0ABFA9-515B6DEF-933229} "POST
    /api/1/station/892337/song/16024201/notify-play HTTP/1.0"
    Roy Smith, Apr 4, 2013
    #13
  14. Steven D'Aprano

    Jason Swails Guest

    On Thu, Apr 4, 2013 at 8:39 AM, Roy Smith <> wrote:

    > In article <>,
    > Jason Swails <> wrote:
    >
    > > The only time I regularly break my rule is for regular expressions (at

    > some
    > > point I may embrace re.X to allow me to break those up, too).

    >
    > re.X is a pretty cool tool for making huge regexes readable. But, it
    > turns out that python's auto-continuation and string literal
    > concatenation rules are enough to let you get much the same effect.
    > Here's a regex we use to parse haproxy log files. This would be utter
    > line noise all run together. This way, it's almost readable :)
    >
    > pattern = re.compile(r'haproxy\[(?P<pid>\d+)]: '
    > r'(?P<client_ip>(\d{1,3}\.){3}\d{1,3}):'
    > r'(?P<client_port>\d{1,5}) '
    >


    For some reason that never occurred to me. I use this technique every
    other time I want to break up a long string, but never for regexes...

    Now I will. I was wary of using re.X since I sometimes use meaningful
    whitespace in my regexes, and I didn't want to have to figure out how to
    prevent them from being ignored... This is a much better solution.

    Thanks,
    Jason
    Jason Swails, Apr 4, 2013
    #14
  15. Steven D'Aprano

    llanitedave Guest

    On Thursday, April 4, 2013 4:52:38 AM UTC-7, Roy Smith wrote:
    > In article <>,
    >
    > llanitedave <> wrote:
    >
    >
    >
    > > I would hate to have to break up this line, for instance:

    >
    > >

    >
    > > self.mainLabel.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName =

    >
    > > "FreeSans"))

    >
    >
    >
    > I would write that as some variation on
    >
    >
    >
    > self.mainLabel.SetFont(wx.Font(12,
    >
    > wx.DEFAULT,
    >
    > wx.NORMAL,
    >
    > wx.BOLD,
    >
    > faceName="FreeSans"))
    >
    >
    >
    > This lets the reader see at a glance that all the arguments go with
    >
    > wx.Font(), not with SetFont(), without having to visually parse and
    >
    > match parenthesis levels.
    >
    >
    >
    > Actually, I would probably break it up further as:
    >
    >
    >
    > my_font = wx.Font(12,
    >
    > wx.DEFAULT,
    >
    > wx.NORMAL,
    >
    > wx.BOLD,
    >
    > faceName="FreeSans")
    >
    > self.mainLabel.SetFont(my_font)
    >
    >
    >
    > The last thing on my mind when deciding how to format this is whether I
    >
    > would be able to punch it onto a single card.


    To each their own, definitely. For myself, I don't see the utility in adding a bunch of what appears to be superfluous horizontal white space at the expense of extra lines to scroll down. I like to limit my scrolling needs in *both* directions.
    (Although I do tend to be fairly generous with blank lines to break up code "paragraphs")
    llanitedave, Apr 4, 2013
    #15
  16. Steven D'Aprano

    Neil Cerutti Guest

    On 2013-04-04, Roy Smith <> wrote:
    > re.X is a pretty cool tool for making huge regexes readable.
    > But, it turns out that python's auto-continuation and string
    > literal concatenation rules are enough to let you get much the
    > same effect. Here's a regex we use to parse haproxy log files.
    > This would be utter line noise all run together. This way, it's
    > almost readable :)
    >
    > pattern = re.compile(r'haproxy\[(?P<pid>\d+)]: '
    > r'(?P<client_ip>(\d{1,3}\.){3}\d{1,3}):'
    > r'(?P<client_port>\d{1,5}) '
    >
    > r'\[(?P<accept_date>\d{2}/\w{3}/\d{4}:)\d{2}){3}\.\d{3})] '
    > r'(?P<frontend_name>\S+) '
    > r'(?P<backend_name>\S+)/'
    > r'(?P<server_name>\S+) '
    > r'(?P<Tq>(-1|\d+))/'
    > r'(?P<Tw>(-1|\d+))/'
    > r'(?P<Tc>(-1|\d+))/'
    > r'(?P<Tr>(-1|\d+))/'
    > r'(?P<Tt>\+?\d+) '
    > r'(?P<status_code>\d{3}) '
    > r'(?P<bytes_read>\d+) '
    > r'(?P<captured_request_cookie>\S+) '
    > r'(?P<captured_response_cookie>\S+) '
    > r'(?P<termination_state>[\w-]{4}) '
    > r'(?P<actconn>\d+)/'
    > r'(?P<feconn>\d+)/'
    > r'(?P<beconn>\d+)/'
    > r'(?P<srv_conn>\d+)/'
    > r'(?P<retries>\d+) '
    > r'(?P<srv_queue>\d+)/'
    > r'(?P<backend_queue>\d+) '
    > r'(\{(?P<request_id>.*?)\} )?'
    > r'(\{(?P<captured_request_headers>.*?)\} )?'
    > r'(\{(?P<captured_response_headers>.*?)\} )?'
    > r'"(?P<http_request>.+)"'
    > )
    >
    > And, for those of you who go running in the other direction every time
    > regex is suggested as a solution, I challenge you to come up with easier
    > to read (or write) code for parsing a line like this (probably
    > hopelessly mangled by the time you read it):
    >
    > 2013-04-03T00:00:00+00:00 localhost haproxy[5199]: 10.159.19.244:57291
    > [02/Apr/2013:23:59:59.811] app-nodes next-song-nodes/web8.songza.com
    > 0/0/3/214/219 200 593 sessionid=NWiX5KGOdvg6dSaA
    > sessionid=NWiX5KGOdvg6dSaA ---- 249/249/149/14/0 0/0
    > {4C0ABFA9-515B6DEF-933229} "POST
    > /api/1/station/892337/song/16024201/notify-play HTTP/1.0"


    The big win from the above seems to me the groupdict result. The
    parsing is also very simple, with virtually no nesting. It's a
    good application of re.

    It seems easy enough to do with str methods, but would it be an
    improvement?

    I ran out of time before the prototype was finished, but here's a
    sketch.


    import re
    import datetime
    import pprint

    s =('2013-04-03T00:00:00+00:00 localhost haproxy[5199]: 10.159.19.244:57291'
    ' [02/Apr/2013:23:59:59.811] app-nodes next-song-nodes/web8.songza.com'
    ' 0/0/3/214/219 200 593 sessionid=NWiX5KGOdvg6dSaA'
    ' sessionid=NWiX5KGOdvg6dSaA ---- 249/249/149/14/0 0/0'
    ' {4C0ABFA9-515B6DEF-933229}'
    ' "POST /api/1/station/892337/song/16024201/notify-play HTTP/1.0"')

    def get_haproxy(s):
    prefix = 'haproxy['
    if s.startswith(prefix):
    return int(s[len(prefix):s.index(']')])
    return False

    def get_client_info(s):
    ip, colon, port = s.partition(':')
    if colon != ':':
    return False
    else:
    return ip, int(port)

    def get_accept_date(s):
    try:
    return datetime.datetime.strptime(s, '[%d/%b/%Y:%H:%M:%S.%f]')
    except ValueError:
    return False

    def get_backend(s):
    name, slash, server = s.partition('/')
    if slash != '/':
    return False
    else:
    return name, server

    def get_track_info(s):
    try:
    return s.split('/')
    except TypeError:
    return False

    matchers = [
    (None, None),
    (None, 'localhost'),
    ('haproxy', get_haproxy),
    (('client_ip', 'client_port'), get_client_info),
    ('accept_date', get_accept_date),
    ('frontend_name', lambda s: s),
    (('backend_name', 'server_name'), get_backend),
    (('Tq', 'Tw', 'Tc', 'Tr', 'Tt'), get_track_info),
    ]
    result = {}

    for i, s in enumerate(s.split()):
    if i < len(matchers): # I'm not finished writing matchers yet.
    key, matcher = matchers
    if matcher is None:
    pass
    else:
    if isinstance(matcher, str):
    value = matcher == s
    else:
    value = matcher(s)
    if value is False:
    raise ValueError('Parse error {}: {} "{}"'.format(
    key, matcher, s))
    if isinstance(key, tuple):
    result.update(zip(*[key, value]))
    elif key is not None:
    result[key] = value
    pprint.pprint(result)

    The engine would need to be improved in implementation and made
    more flexible once it's working and tested. I think the error
    handling is a good feature and the ability to customize parsing
    and return custom types is cool.

    --
    Neil Cerutti
    Neil Cerutti, Apr 4, 2013
    #16
  17. On 04/03/2013 09:36 PM, Steven D'Aprano wrote:
    > Although PEP 8 is only compulsory for the Python standard library, many
    > users like to stick to PEP 8 for external projects.
    >
    > http://www.python.org/dev/peps/pep-0008/
    >
    > With perhaps one glaring exception: many people hate, or ignore, PEP 8's
    > recommendation to limit lines to 80 characters. (Strictly speaking, 79
    > characters.)
    >
    >
    > Here is a good defence of 80 char lines:
    >
    > http://wrongsideofmemphis.com/2013/03/25/80-chars-per-line-is-great/
    >
    >
    >



    I think one important consideration that wasn't mentioned yet is one of
    Python principles: practicality beats purity.

    I can see how someone could have a preference for 80 char width, there
    are some valid reasons to prefer it. I think other reasons to prefer
    (slightly) longer width outweigh them, but that's a judgement call.

    However, if you work with other people's code, you will surely run into
    all kinds of widths, 100, 120, 140+, etc. For someone with a rigid 80
    limit, it's a real pain. I feel that somewhere around 100 width, must be
    the reasonable middle ground: for me at soft 105 limit, editing 80 limit
    code feels almost like my own, in fact the range of 80-110 is going to
    fit neatly into my setup without any hassle.

    120 is minimal hassle: I adjust Gvim to take a bit more space, resize
    browser to take a bit less space and I'm set.

    140 is a bit uncomfortable, but I generally notice that even when people
    code to 140 limit, nearly all of their lines are actually going to be at
    about 120 limit at most, with only a few offenders, so it's trivial to
    adjust to 120 limit.

    If people go over 140, that conclusively proves they're smoking crack
    and the code needs to be refactored anyway.


    I also find the argument about 80 width used in books a little odd. I
    read webpages with 100-140 widths all the time with not the slightest
    problem. As far as I know, no browser in existence lets you uniformly
    adjust all pages to wrap at 80 limit except for lynx/links; if it was
    hard to read at wider sizes, surely there would be at least one
    graphical browser that would give that option (and get all the user
    share from other browsers?)

    Code is rather different from regular text. I would not want my books
    formatted like this:

    The story had held us, round the fire, sufficiently breathless, but
    except the obvious
    remark that it was
    gruesome, as,

    on Christmas Eve in an old house, a strange tale should essentially be,
    I remember no comment uttered till somebody
    happened to say that
    it was the only case he had met in which such a visitation
    had fallen on a
    child.


    Nor am I (warning: understatement) particularly enthusiastic about
    editing code that looks like (formatted to 72 width):


    try: request = self.request_class(environ) except UnicodeDecodeError:
    logger.warning('Bad Request (UnicodeDecodeError)',
    exc_info=sys.exc_info(), extra={ 'status_code': 400, }) response =
    http.HttpResponseBadRequest() else: response =
    self.get_response(request)

    response._handler_class = self.__class__

    try: status_text = STATUS_CODE_TEXT[response.status_code] except
    KeyError: status_text = 'UNKNOWN STATUS CODE' status = '%s %s' %
    (response.status_code, status_text) response_headers = [(str(k), str(v))
    for k, v in response.items()] for c in response.cookies.values():
    response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
    start_response(force_str(status), response_headers) return response


    -m



    --
    Lark's Tongue Guide to Python: http://lightbird.net/larks/
    Mitya Sirenef, Apr 4, 2013
    #17
  18. On 4 April 2013 12:09, Tim Chase <> wrote:

    > On 2013-04-04 08:43, Peter Otten wrote:
    > > llanitedave wrote:
    > >> self.mainLabel.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD,

    > faceName = "FreeSans"))
    > >
    > > I think I would prefer
    > >
    > > labelfont = wx.Font(
    > > pointSize=12,
    > > style=wx.DEFAULT,
    > > family=wx.NORMAL,
    > > weight=wx.BOLD,
    > > faceName="FreeSans")
    > > self.mainLabel.SetFont(labelfont)

    >
    > +1
    > The only change I'd make to this suggestion would be to add a
    > semi-superfluous comma+newline after the last keyword argument too:
    >
    > labelfont = wx.Font(
    > pointSize=12,
    > style=wx.DEFAULT,
    > family=wx.NORMAL,
    > weight=wx.BOLD,
    > faceName="FreeSans",
    > )
    >


    Since we're all showing opinions, I've always prefered the typical block
    indentation:

    labelfont = wx.Font(
    pointSize=12,
    style=wx.DEFAULT,
    family=wx.NORMAL,
    weight=wx.BOLD,
    faceName="FreeSans",
    ) # Not indented here

    as

    A(
    B(
    C,
    D,
    E,
    )
    )

    reads a lot cleaner than

    A(
    B(
    C,
    D,
    E
    )
    )

    which makes diffs cleaner when you need to insert something after
    > faceName:
    >

    <DIFS SNIP>

    That is a very good point :).

    Additionally, if there are lots of keyword parameters like this, I'd
    > be tempted to keep them in sorted order for ease of tracking them
    > down (though CSS has long-standing arguments on how properties should
    > be ordered, so to each their own on this).
    >


    Personally I'd rarely be tempted to put more than 9 or so arguments
    directly into a function or class. Most of the time I can imagine unpacking
    (or equiv.) would look much more readable in the circumstances that apply.
    Joshua Landau, Apr 4, 2013
    #18
  19. Roy Smith <> writes:

    > In article <>,
    > Jason Swails <> wrote:
    >
    >> The only time I regularly break my rule is for regular expressions (at some
    >> point I may embrace re.X to allow me to break those up, too).

    >
    > re.X is a pretty cool tool for making huge regexes readable. But, it
    > turns out that python's auto-continuation and string literal
    > concatenation rules are enough to let you get much the same effect.
    > Here's a regex we use to parse haproxy log files. This would be utter
    > line noise all run together. This way, it's almost readable :)
    >
    > pattern = re.compile(r'haproxy\[(?P<pid>\d+)]: '
    > r'(?P<client_ip>(\d{1,3}\.){3}\d{1,3}):'
    > r'(?P<client_port>\d{1,5}) '
    >
    > r'\[(?P<accept_date>\d{2}/\w{3}/\d{4}:)\d{2}){3}\.\d{3})] '
    > r'(?P<frontend_name>\S+) '
    > r'(?P<backend_name>\S+)/'
    > r'(?P<server_name>\S+) '
    > r'(?P<Tq>(-1|\d+))/'
    > r'(?P<Tw>(-1|\d+))/'
    > r'(?P<Tc>(-1|\d+))/'
    > r'(?P<Tr>(-1|\d+))/'
    > r'(?P<Tt>\+?\d+) '
    > r'(?P<status_code>\d{3}) '
    > r'(?P<bytes_read>\d+) '
    > r'(?P<captured_request_cookie>\S+) '
    > r'(?P<captured_response_cookie>\S+) '
    > r'(?P<termination_state>[\w-]{4}) '
    > r'(?P<actconn>\d+)/'
    > r'(?P<feconn>\d+)/'
    > r'(?P<beconn>\d+)/'
    > r'(?P<srv_conn>\d+)/'
    > r'(?P<retries>\d+) '
    > r'(?P<srv_queue>\d+)/'
    > r'(?P<backend_queue>\d+) '
    > r'(\{(?P<request_id>.*?)\} )?'
    > r'(\{(?P<captured_request_headers>.*?)\} )?'
    > r'(\{(?P<captured_response_headers>.*?)\} )?'
    > r'"(?P<http_request>.+)"'
    > )
    >
    > And, for those of you who go running in the other direction every time
    > regex is suggested as a solution, I challenge you to come up with easier
    > to read (or write) code for parsing a line like this (probably
    > hopelessly mangled by the time you read it):
    >
    > 2013-04-03T00:00:00+00:00 localhost haproxy[5199]: 10.159.19.244:57291
    > [02/Apr/2013:23:59:59.811] app-nodes next-song-nodes/web8.songza.com
    > 0/0/3/214/219 200 593 sessionid=NWiX5KGOdvg6dSaA
    > sessionid=NWiX5KGOdvg6dSaA ---- 249/249/149/14/0 0/0
    > {4C0ABFA9-515B6DEF-933229} "POST
    > /api/1/station/892337/song/16024201/notify-play HTTP/1.0"


    Is using csv.DictReader with delimiter=' ' not sufficient for this? I
    did not actually read the regular expression in its entirety.

    --
    regards,
    kushal
    Kushal Kumaran, Apr 4, 2013
    #19
  20. Steven D'Aprano

    jmfauth Guest

    On 4 avr, 03:36, Steven D'Aprano <steve
    > wrote:
    > Although PEP 8 is only compulsory for the Python standard library, many
    > users like to stick to PEP 8 for external projects.
    >
    > http://www.python.org/dev/peps/pep-0008/
    >
    > With perhaps one glaring exception: many people hate, or ignore, PEP 8's
    > recommendation to limit lines to 80 characters. (Strictly speaking, 79
    > characters.)
    >
    > Here is a good defence of 80 char lines:
    >
    > http://wrongsideofmemphis.com/2013/03/25/80-chars-per-line-is-great/
    >
    > --
    > Steven


    -----

    With "unicode fonts", where even the monospaced fonts
    present char widths with a variable width depending on
    the unicode block (obvious reasons), speaking of a "text
    width" in chars has not even a sense.

    jmf
    jmfauth, Apr 4, 2013
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. wwj
    Replies:
    7
    Views:
    526
  2. wwj
    Replies:
    24
    Views:
    2,462
    Mike Wahler
    Nov 7, 2003
  3. Ben Pfaff
    Replies:
    5
    Views:
    455
    Tristan Miller
    Jan 17, 2004
  4. Steffen Fiksdal

    void*, char*, unsigned char*, signed char*

    Steffen Fiksdal, May 8, 2005, in forum: C Programming
    Replies:
    1
    Views:
    565
    Jack Klein
    May 9, 2005
  5. lovecreatesbeauty
    Replies:
    1
    Views:
    994
    Ian Collins
    May 9, 2006
Loading...

Share This Page