Why do this?

Discussion in 'Python' started by Matthew Warren, Oct 5, 2006.

  1. Ok, not really python focused, but it feels like the people here could
    explain it for me :)

    Now, I started programming when I was 8 with BBC Basic.

    I never took any formal classes however, and I have never become an
    expert programmer. I'm an average/hobbyist programmer with quite a few
    languages under my belt but I cant do any really fancy tricks with any
    of them. (although Python might be nudging me into more advanced things,
    now I'm starting to get what all the __method__ thingies and operators
    are all about)

    I learned over the years to do things like the following, and I like
    doing it like this because of readability, something Python seems to
    focus on :-

    Print "There are "+number+" ways to skin a "+furryanimal

    But nowadays, I see things like this all over the place;

    print("There are %s ways to skin a %s" % (number, furryanimal))

    Now I understand there can be additional formatting benefits when
    dealing with numbers, decimal places etc.. But to me, for strings, the
    second case is much harder to read than the first.

    I hope I'm not being dense.

    The result is that I have pathalogically avoided print "%s" % (thing)
    because it seems to just over complicate things.


    Ta, :)

    Matt.





    This email is confidential and may be privileged. If you are not the intended recipient please notify the sender immediately and delete the email from your computer.

    You should not copy the email, use it for any purpose or disclose its contents to any other person.
    Please note that any views or opinions presented in this email may be personal to the author and do not necessarily represent the views or opinions of Digica.
    It is the responsibility of the recipient to check this email for the presence of viruses. Digica accepts no liability for any damage caused by any virus transmitted by this email.

    UK: Phoenix House, Colliers Way, Nottingham, NG8 6AT UK
    Reception Tel: + 44 (0) 115 977 1177
    Support Centre: 0845 607 7070
    Fax: + 44 (0) 115 977 7000
    http://www.digica.com

    SOUTH AFRICA: Building 3, Parc du Cap, Mispel Road, Bellville, 7535, South Africa
    Tel: + 27 (0) 21 957 4900
    Fax: + 27 (0) 21 948 3135
    http://www.digica.com
    Matthew Warren, Oct 5, 2006
    #1
    1. Advertising

  2. Matthew Warren

    Duncan Booth Guest

    "Matthew Warren" <> wrote:

    > Print "There are "+number+" ways to skin a "+furryanimal
    >
    > But nowadays, I see things like this all over the place;
    >
    > print("There are %s ways to skin a %s" % (number, furryanimal))
    >
    > Now I understand there can be additional formatting benefits when
    > dealing with numbers, decimal places etc.. But to me, for strings, the
    > second case is much harder to read than the first.
    >


    apart from the spurious parentheses you added in the second one, you also
    missed out this variant:

    print "There are", number, "ways to skin a", furryanimal

    That only works for print though, not for other uses of strings, but it is
    related to the main reason I use format strings instead of concatenation.

    The problem I have with your first option is the large number of times I've
    written:

    print "There are"+number+"ways to skin a"+furryanimal

    or at least something equivalent to it. If I try to make the same mistake
    with a format string it jumps out to me as wrong:

    "There are%sways to skin a%s" % (number, furryanimal)

    Also, having a variable of type str called 'number' seems perverse (and
    probably error prone), so I suspect I might need something like:

    print "There are "+str(number)+" ways to skin a "+furryanimal

    but the format string does the conversion for free.

    The other main reason for preferring format strings is that they make it
    easier to refactor the code. If you ever want to move the message away from
    where the formatting is done then it's a lot easier to extract a single
    string than it is to clean up the concatenation.
    Duncan Booth, Oct 5, 2006
    #2
    1. Advertising

  3. In <>, Matthew Warren
    wrote:

    > I learned over the years to do things like the following, and I like
    > doing it like this because of readability, something Python seems to
    > focus on :-
    >
    > Print "There are "+number+" ways to skin a "+furryanimal
    >
    > But nowadays, I see things like this all over the place;
    >
    > print("There are %s ways to skin a %s" % (number, furryanimal))
    >
    > Now I understand there can be additional formatting benefits when
    > dealing with numbers, decimal places etc.. But to me, for strings, the
    > second case is much harder to read than the first.


    For me it's the other way around -- I find the second one more readable
    especially without syntax highlighting to see which characters are inside
    and which are outside the quotes.

    With the second one there's a clear visual separation of the string
    literal and the variables, even without colors.

    Another advantage of the second way is much easier localization and other
    tasks where the sentence itself is not hardcoded but read from files,
    databases, etc.

    And the '%s' automatically converts the objects to strings. The
    equivalent to the second example without string formatting would be::

    print 'There are' + str(number) + ' ways to skin a ' + str(furryanimal)

    Ciao,
    Marc 'BlackJack' Rintsch
    Marc 'BlackJack' Rintsch, Oct 5, 2006
    #3
  4. Matthew Warren

    Ivan Voras Guest

    Duncan Booth wrote:

    > print "There are"+number+"ways to skin a"+furryanimal
    >
    > or at least something equivalent to it. If I try to make the same mistake
    > with a format string it jumps out to me as wrong:
    >
    > "There are%sways to skin a%s" % (number, furryanimal)


    Related to this, formatting with sequences is also much more readable
    when there are complex interpunction and quoting characters present,
    like this:

    print "'"+var1+"','"+var2'"+","+var3

    the above is much more readable as

    print "'%s', '%s', %s" % (var1, var2, var3)
    Ivan Voras, Oct 5, 2006
    #4
  5. Le jeudi 05 octobre 2006 13:16, Ivan Voras a écrit :
    > print "'"+var1+"','"+var2'"+","+var3
    >
    > the above is much more readable as
    >
    > print "'%s', '%s', %s" % (var1, var2, var3)


    It feels not IMO, one proof I see is that you forgot the spaces after periods
    in your first example, and it's even not easy to figure it out...

    In fact this is a typical case I replace the first by the second, when the
    string comes a little complex.

    --
    _____________

    Maric Michaud
    _____________

    Aristote - www.aristote.info
    3 place des tapis
    69004 Lyon
    Tel: +33 426 880 097
    Maric Michaud, Oct 5, 2006
    #5
  6. On Thu, Oct 05, 2006 at 10:48:36AM +0000, Duncan Booth wrote:
    > The other main reason for preferring format strings is that they make it
    > easier to refactor the code. If you ever want to move the message away from
    > where the formatting is done then it's a lot easier to extract a single
    > string than it is to clean up the concatenation.


    This is a good point imho.
    I often do things like this:

    sql = a_complex_select_sql % (id_foo, value_bar, ...)
    cursor.execute(sql)

    inside the body of a function (or a class method), where
    a_complex_select_sql is a string, containing several %s, %d ecc.,
    that is defined globally (or somewhere else in the class).

    c.
    --
    "Thought is only a flash between two long nights,
    but this flash is everything."
    (H. Poincaré)
    Corrado Gioannini, Oct 5, 2006
    #6
  7. On Thu, 5 Oct 2006 11:28:08 +0100, "Matthew Warren"
    <> declaimed the following in comp.lang.python:

    >
    > Now, I started programming when I was 8 with BBC Basic.
    >

    Remember what the acronym BASIC stands for?

    >
    > I learned over the years to do things like the following, and I like
    > doing it like this because of readability, something Python seems to
    > focus on :-
    >
    > Print "There are "+number+" ways to skin a "+furryanimal
    >

    I'd consider that a convenience method (heck, "print" [Python is
    case sensitive] is a convenience statement -- the formal statement would
    be sys.stdout.write(....)).

    Many major languages (going back to FORTRAN, COBOL, C, Ada) require
    explicit formatting control. In Ada the above would probably be
    something like:

    put('There are '); -- I forget if Ada uses " or ' for strings
    put(number);
    put(' ways to skin a ');
    put_line(furryanimal);
    {granted, if it is known that all items are strings, then:
    put_line('There are ' &
    number &
    ' ways to skin a ' &
    furryanimal);
    }

    > But nowadays, I see things like this all over the place;
    >
    > print("There are %s ways to skin a %s" % (number, furryanimal))
    >


    At present, the outer ( ) are superfluous. The main features are
    that one can do more than %s... %20s makes a field 20 characters wide...
    %4.4x makes a zero-filled hexadecimal value... And one can easily
    "internationalize" output by reading formats from a data file...

    mess_skinning = ifile.readline() #where ifile is opened to the
    #needed language


    print mess_skinning % (number, furryanimal)
    --
    Wulfraed Dennis Lee Bieber KD6MOG

    HTTP://wlfraed.home.netcom.com/
    (Bestiaria Support Staff: )
    HTTP://www.bestiaria.com/
    Dennis Lee Bieber, Oct 6, 2006
    #7
  8. Matthew Warren

    hanumizzle Guest

    On 10/6/06, Dennis Lee Bieber <> wrote:
    > On Thu, 5 Oct 2006 11:28:08 +0100, "Matthew Warren"
    > <> declaimed the following in comp.lang.python:
    >
    > >
    > > Now, I started programming when I was 8 with BBC Basic.
    > >

    > Remember what the acronym BASIC stands for?


    Boobie-drawing Adolescent Symbolic Instruction Code.

    -- Theerasak
    hanumizzle, Oct 6, 2006
    #8
  9. "Dennis Lee Bieber" <> wrote:

    > On Thu, 5 Oct 2006 11:28:08 +0100, "Matthew Warren"
    > <> declaimed the following in comp.lang.python:
    >
    > >
    > > Now, I started programming when I was 8 with BBC Basic.
    > >

    > Remember what the acronym BASIC stands for?


    8<-----------------------------------------------

    yes

    - Hendrik
    Hendrik van Rooyen, Oct 6, 2006
    #9
  10. Matthew Warren

    Guest

    Nobody's mentioned the ability to save a formatted string and then
    substitute the variables later...

    string = "There are %s ways to skin a %s"

    print string % (3, "furry animal")
    print string % (166, "beast")

    ~half.italian

    Matthew Warren wrote:
    > Ok, not really python focused, but it feels like the people here could
    > explain it for me :)
    >
    > Now, I started programming when I was 8 with BBC Basic.
    >
    > I never took any formal classes however, and I have never become an
    > expert programmer. I'm an average/hobbyist programmer with quite a few
    > languages under my belt but I cant do any really fancy tricks with any
    > of them. (although Python might be nudging me into more advanced things,
    > now I'm starting to get what all the __method__ thingies and operators
    > are all about)
    >
    > I learned over the years to do things like the following, and I like
    > doing it like this because of readability, something Python seems to
    > focus on :-
    >
    > Print "There are "+number+" ways to skin a "+furryanimal
    >
    > But nowadays, I see things like this all over the place;
    >
    > print("There are %s ways to skin a %s" % (number, furryanimal))
    >
    > Now I understand there can be additional formatting benefits when
    > dealing with numbers, decimal places etc.. But to me, for strings, the
    > second case is much harder to read than the first.
    >
    > I hope I'm not being dense.
    >
    > The result is that I have pathalogically avoided print "%s" % (thing)
    > because it seems to just over complicate things.
    >
    >
    > Ta, :)
    >
    > Matt.
    >
    >
    >
    >
    >
    > This email is confidential and may be privileged. If you are not the intended recipient please notify the sender immediately and delete the email from your computer.
    >
    > You should not copy the email, use it for any purpose or disclose its contents to any other person.
    > Please note that any views or opinions presented in this email may be personal to the author and do not necessarily represent the views or opinions of Digica.
    > It is the responsibility of the recipient to check this email for the presence of viruses. Digica accepts no liability for any damage caused by any virus transmitted by this email.
    >
    > UK: Phoenix House, Colliers Way, Nottingham, NG8 6AT UK
    > Reception Tel: + 44 (0) 115 977 1177
    > Support Centre: 0845 607 7070
    > Fax: + 44 (0) 115 977 7000
    > http://www.digica.com
    >
    > SOUTH AFRICA: Building 3, Parc du Cap, Mispel Road, Bellville, 7535, South Africa
    > Tel: + 27 (0) 21 957 4900
    > Fax: + 27 (0) 21 948 3135
    > http://www.digica.com
    , Oct 6, 2006
    #10
  11. Matthew Warren

    Duncan Booth Guest

    Corrado Gioannini <> wrote:

    > I often do things like this:
    >
    > sql = a_complex_select_sql % (id_foo, value_bar, ...)
    > cursor.execute(sql)
    >
    > inside the body of a function (or a class method), where
    > a_complex_select_sql is a string, containing several %s, %d ecc.,
    > that is defined globally (or somewhere else in the class).
    >

    I hope you have a good reason why you don't do:

    cursor.execute(a_complex_select_sql, (id_foo, value_bar, ...))

    instead.
    Duncan Booth, Oct 6, 2006
    #11
  12. On Fri, Oct 06, 2006 at 10:09:14AM +0000, Duncan Booth wrote:
    > I hope you have a good reason why you don't do:
    >
    > cursor.execute(a_complex_select_sql, (id_foo, value_bar, ...))
    >
    > instead.


    hehe.
    i was just trying to be didactic, simplifying the actual situation.
    (anyway, sometimes i had to print, or store, the sql statement, or
    to execute the same sql statement on different databases etc. etc..)

    regards,
    c.
    --
    no, sono sempre io, non mi cambierete quel che ho dentro
    forse ho solo un'altra faccia
    ho più cicatrici di prima, sorrido un po' meno,
    forse penso di più.
    (Kina)
    Corrado Gioannini, Oct 6, 2006
    #12
  13. In message <Xns98547173763B6duncanbooth@127.0.0.1>, Duncan Booth wrote:

    > Corrado Gioannini <> wrote:
    >
    >> I often do things like this:
    >>
    >> sql = a_complex_select_sql % (id_foo, value_bar, ...)
    >> cursor.execute(sql)
    >>
    >> inside the body of a function (or a class method), where
    >> a_complex_select_sql is a string, containing several %s, %d ecc.,
    >> that is defined globally (or somewhere else in the class).
    >>

    > I hope you have a good reason why you don't do:
    >
    > cursor.execute(a_complex_select_sql, (id_foo, value_bar, ...))
    >
    > instead.


    I use the above when I can, when I can't I fall back on
    <http://groups.google.co.nz/groups?selm=efc5b3$can$>,
    <http://groups.google.co.nz/groups?selm=efhn5v$fia$>.
    Lawrence D'Oliveiro, Oct 9, 2006
    #13
  14. Matthew Warren

    Duncan Booth Guest

    Lawrence D'Oliveiro <_zealand> wrote:

    > I use the above when I can, when I can't I fall back on
    ><http://groups.google.co.nz/groups?selm=efc5b3$can$>,
    ><http://groups.google.co.nz/groups?selm=efhn5v$fia$>.


    Yes, so you said, but you never came up with a convincing use case where
    that function was better than using the parameterised queries.
    Duncan Booth, Oct 9, 2006
    #14
  15. In message <Xns985755C711158duncanbooth@127.0.0.1>, Duncan Booth wrote:

    > Lawrence D'Oliveiro <_zealand> wrote:
    >
    >> I use the above when I can, when I can't I fall back on
    >><http://groups.google.co.nz/groups?selm=efc5b3$can$>,
    >><http://groups.google.co.nz/groups?selm=efhn5v$fia$>.

    >
    > Yes, so you said, but you never came up with a convincing use case where
    > that function was better than using the parameterised queries.


    First of all, the parametrization doesn't handle wildcards, as we discussed
    previously.

    Secondly, it's less convenient for cases where a dynamic query is being
    built. I previously gave the SQLStringList example. If that's not enough,
    here's another (simple) one:

    Conditions = []
    if Name != None :
    Conditions.append("name = %s" % SQLString(Name))
    #end if
    if Address != None :
    Conditions.append("address = %s" % SQLString(Address))
    #end if
    if PhoneNr != None :
    Conditions.append("phone_nr = %s" % SQLString(PhoneNr))
    #end if
    Query = "select * from table"
    if len(Conditions) != 0 :
    Query += " where " + " and ".join(Conditions)
    #end if
    Lawrence D'Oliveiro, Oct 9, 2006
    #15
  16. Lawrence D'Oliveiro wrote:

    > Secondly, it's less convenient for cases where a dynamic query is being
    > built. I previously gave the SQLStringList example. If that's not enough,
    > here's another (simple) one:
    >
    > Conditions = []
    > if Name != None :
    > Conditions.append("name = %s" % SQLString(Name))
    > #end if
    > if Address != None :
    > Conditions.append("address = %s" % SQLString(Address))
    > #end if
    > if PhoneNr != None :
    > Conditions.append("phone_nr = %s" % SQLString(PhoneNr))
    > #end if
    > Query = "select * from table"
    > if len(Conditions) != 0 :
    > Query += " where " + " and ".join(Conditions)
    > #end if


    now that's some remarkably ugly Python code. it's well-known that people can
    write Fortran in all languages, but writing Visual Basic in Python? (shudder)

    here's a straight-forward and more efficient translation of that code:

    where = []; params = []
    if name is not None:
    where.append("name=?"); params.append(name)
    if address is not None:
    where.append("address=?"); params.append(address)
    if phone_nr is not None:
    where.append("phone_nr=?"); params.append(phone_nr)
    query = "select * from table"
    if where:
    query += " where " + " and ".join(where)
    cursor.execute(query, tuple(params))

    which works for all data types and without any error-prone explicit quotation non-
    sense, and which can be trivially refactored into

    where = []; params = []
    def append(column, value):
    if value is not None:
    where.append(column+"=?"); params.append(value)

    append("name", name)
    append("address", address)
    append("phone_nr", phone_nr)

    query = "select * from table"
    if where:
    query += " where %s " + " and ".join(where)

    cursor.execute(query, tuple(params))

    which scales a lot better if when you're adding more fields, and which can be trivially
    refactored into a full statement builder:

    def select(table, **kw):
    where = []; params = []
    for column, value in kw.items():
    if value is not None:
    where.append(column+"=?")
    params.append(value)
    query = "select * from " + table
    if where:
    query += " where " + " and ".join(where)
    return query, tuple(params)

    cursor.execute(*select("table", name=name, address=address, phone_nr=phone_nr))

    where the "select" function can of course be put in a support library and reused every-
    where you make simple selects; alternatively, you can wrap the whole thing into a some-
    thing like

    class where_statement:
    def __init__(self, db):
    self.where = []
    self.params = []
    if db.paramstyle == "qmark":
    self.marker = "?"
    if db.paramstyle == "format":
    self.marker = "%s"
    else:
    raise NotImplementedError(
    "unsupported parameter style: %r" % db.paramstyle
    )
    def __setitem__(self, column, value):
    if value is not None:
    self.where.append(column+"="+self.marker)
    self.params.append(value)
    def __str__(self):
    if not self.where:
    return ""
    return " where " + " and ".join(self.where)
    def __iter__(self):
    return iter(self.params)

    where = where_statement(database)
    where["name"] = name
    where["address"] = address
    where["phone_nr"] = phone_nr
    cursor.execute("select * from table" + str(where), tuple(where))

    which actually protests if you run it on a database that doesn't use the same para-
    meter markers, and can be trivially extended to support more DB-API variants.

    or, of course, refactored into something that's even easier to use for the actual
    use cases.

    this is Python, after all, and as we all know, "the joy of coding Python should be
    in seeing short, concise, readable classes that express a lot of action in a small
    amount of clear code - not in reams of trivial code that bores the reader to death".

    </F>
    Fredrik Lundh, Oct 9, 2006
    #16
  17. Matthew Warren

    Steve Holden Guest

    Fredrik Lundh wrote:
    > Lawrence D'Oliveiro wrote:
    >
    >
    >>Secondly, it's less convenient for cases where a dynamic query is being
    >>built. I previously gave the SQLStringList example. If that's not enough,
    >>here's another (simple) one:
    >>
    >>Conditions = []
    >>if Name != None :
    >> Conditions.append("name = %s" % SQLString(Name))
    >>#end if
    >>if Address != None :
    >> Conditions.append("address = %s" % SQLString(Address))
    >>#end if
    >>if PhoneNr != None :
    >> Conditions.append("phone_nr = %s" % SQLString(PhoneNr))
    >>#end if
    >>Query = "select * from table"
    >>if len(Conditions) != 0 :
    >> Query += " where " + " and ".join(Conditions)
    >>#end if

    >
    >
    > now that's some remarkably ugly Python code. it's well-known that people can
    > write Fortran in all languages, but writing Visual Basic in Python? (shudder)

    [...]
    > this is Python, after all, and as we all know, "the joy of coding Python should be
    > in seeing short, concise, readable classes that express a lot of action in a small
    > amount of clear code - not in reams of trivial code that bores the reader to death".
    >

    I especially liked the #end if comments after the single guarded lines.

    regards
    Steve
    --
    Steve Holden +44 150 684 7255 +1 800 494 3119
    Holden Web LLC/Ltd http://www.holdenweb.com
    Skype: holdenweb http://holdenweb.blogspot.com
    Recent Ramblings http://del.icio.us/steve.holden
    Steve Holden, Oct 9, 2006
    #17
  18. Matthew Warren

    Duncan Booth Guest

    Lawrence D'Oliveiro <_zealand> wrote:

    >>> I use the above when I can, when I can't I fall back on
    >>><http://groups.google.co.nz/groups?selm=efc5b3$can$>,
    >>><http://groups.google.co.nz/groups?selm=efhn5v$fia$>.

    >>
    >> Yes, so you said, but you never came up with a convincing use case
    >> where that function was better than using the parameterised queries.

    >
    > First of all, the parametrization doesn't handle wildcards, as we
    > discussed previously.


    No, your separate function for escaping wildcards is fine, and works in
    conjunction with parameterized queries. It's the SQLString function you
    never managed to justify.

    > Secondly, it's less convenient for cases where a dynamic query is being
    > built. I previously gave the SQLStringList example. If that's not enough,
    > here's another (simple) one:


    See Frederik's excellent response on this point.
    Duncan Booth, Oct 9, 2006
    #18
    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. =?Utf-8?B?VGltOjouLg==?=

    Why, why, why???

    =?Utf-8?B?VGltOjouLg==?=, Jan 27, 2005, in forum: ASP .Net
    Replies:
    6
    Views:
    550
    Juan T. Llibre
    Jan 27, 2005
  2. Horace Nunley

    why why why does function not work

    Horace Nunley, Sep 27, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    445
    =?Utf-8?B?UGV0ZXIgQnJvbWJlcmcgW0MjIE1WUF0=?=
    Sep 27, 2006
  3. Mr. SweatyFinger

    VWD why why why

    Mr. SweatyFinger, Nov 28, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    369
    =?Utf-8?B?Q2lhcmFuIE8nJycnRG9ubmVsbA==?=
    Dec 21, 2006
  4. Mr. SweatyFinger

    why why why why why

    Mr. SweatyFinger, Nov 28, 2006, in forum: ASP .Net
    Replies:
    4
    Views:
    855
    Mark Rae
    Dec 21, 2006
  5. Mr. SweatyFinger
    Replies:
    2
    Views:
    1,744
    Smokey Grindel
    Dec 2, 2006
Loading...

Share This Page