Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

semi-concatenated strings

8 views
Skip to first unread message

Grant Griffin

unread,
May 30, 2002, 3:49:58 PM5/30/02
to
Hi Gang,

I discovered today that strings can sometimes be concatenated without using a
"+":

ActivePython 2.2.1 Build 222 (ActiveState Corp.) based on
Python 2.2.1 (#34, Apr 15 2002, 09:51:39) [MSC 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 'one' ' plus ' 'two'
>>> a
'one plus two'

I discovered this, of course, while making a mistake like this:

>>> a = ['zero', 'one'
... 'two', 'three']
>>> a
['zero', 'onetwo', 'three']

(Note the missing comma after 'one'.)

Is there some grand purpose here, or is this just a bug in the parser?

errors-should-never-pass-silent-ly y'rs,

=g2

Steven Majewski

unread,
May 30, 2002, 4:36:52 PM5/30/02
to

On 30 May 2002, Grant Griffin wrote:

> I discovered today that strings can sometimes be concatenated without using a
> "+":

> >>> a = 'one' ' plus ' 'two'
> >>> a
> 'one plus two'

[...]

> Is there some grand purpose here, or is this just a bug in the parser?

It's a feature, not a bug:

I believe that it predates the triple quoted strings as a way to have
very long multiline strings. ( I'ld have to dig thru the news archives
or the changelog to be certain about the history. )

(There should only be HOW MANY WAYS?! ;-)

-- Steve Majewski


Fredrik Lundh

unread,
May 30, 2002, 5:06:38 PM5/30/02
to
Grant Griffin wrote:
>
> I discovered today that strings can sometimes be concatenated
> without using a "+":

had you read the language reference, you might have discovered
this long ago:

2.4.2 String literal concatenation
http://www.python.org/doc/current/ref/string-catenation.html

and Python's not the only language doing this, of course; e.g. see:

http://www.lysator.liu.se/c/rat/c1.html#3-1-4

</F>

<!-- (the eff-bot guide to) the python standard library:
http://www.pythonware.com/people/fredrik/librarybook.htm
-->


Skip Montanaro

unread,
May 30, 2002, 4:39:20 PM5/30/02
to

Grant> I discovered today that strings can sometimes be concatenated
Grant> without using a "+":

Actually, string literals can always be concatenated without adding them.

Grant> I discovered this, of course, while making a mistake like this:

>>> a = ['zero', 'one'
... 'two', 'three']
>>> a
['zero', 'onetwo', 'three']

Yup, that's just how it's supposed to work. It makes it easier to compose
long strings. For example, I have code like this that queries a database:

rows = self.executesql("select cities.city, state, country"
" from cities, venues, events, addresses"
" where cities.city like %s"
" and events.active = 1"
" and venues.address = addresses.id"
" and addresses.city = cities.id"
" and events.venue = venues.id",
(city,))

At compile time all those strings are concatenated into one long string.
The select statement remains readable for me, but is represented as a single
string constant in the generated bytecode.

--
Skip Montanaro (sk...@pobox.com - http://www.mojam.com/)
Boycott Netflix - they spam - http://www.musi-cal.com/~skip/netflix.html

jodoin

unread,
May 30, 2002, 5:10:45 PM5/30/02
to
Actually this is not an error in the Parser. It is well documented that you can do this. In the grammar rules
a string can imediately follow another string.  This rule is specified so that you will not have to use
as many backslashes. For more information see the Python Language Specification in section 2.4.2 String Literal concatenation

Cheers,

-- 
Georges Jodoin
jod...@cpsc.ucalgary.ca
 

Chris Liechti

unread,
May 30, 2002, 5:26:13 PM5/30/02
to
Steven Majewski <sd...@Virginia.EDU> wrote in
news:Pine.OSX.4.43.02053...@d-128-61-180.bootp.Virginia.
EDU:

it has applications where only this method works.
i think the example is in the docs. e.g. when you want to comment on a
complicated string, like an regex:

re.compile("([ab])+" #group one (at least one occurence of either a or b)
"(hello)*" #group two (optional)
)

(ok + works too but its not the same. the "'a' 'b'" concatenated string is
one, with + you have many strings that are concatenated at runtime.)

the feature is also known in C, where it's important to do some
preprocessor magic.

chris

--
Chris <clie...@gmx.net>

Delaney, Timothy

unread,
May 30, 2002, 7:28:19 PM5/30/02
to
> From: Skip Montanaro [mailto:sk...@pobox.com]

>
> long strings. For example, I have code like this that
> queries a database:
>
> rows = self.executesql("select cities.city, state, country"
> " from cities, venues, events, addresses"
> " where cities.city like %s"
> " and events.active = 1"
> " and venues.address = addresses.id"
> " and addresses.city = cities.id"
> " and events.venue = venues.id",
> (city,))

[lines undented somewhat to prevent wrapping ...]

Just wondering Skip ... why would you write this rather than a triple-quoted
string?

rows = self.executesql("""
select cities.city, state, country
from cities, venues, events, addresses
where cities.city like %s
and events.active = 1
and venues.address = addresses.id
and addresses.city = cities.id
and events.venue = venues.id
""", (city,))

which to me looks much cleaner and is much easier to modify.

Of course, I also would have bound the SQL to a name first ...

sql = """


select cities.city, state, country
from cities, venues, events, addresses
where cities.city like %s
and events.active = 1
and venues.address = addresses.id
and addresses.city = cities.id
and events.venue = venues.id
"""

rows = self.executesql(sql.strip(), (city,))

I've yet to find a place where I've had a use for concatenating string
literals.

Tim Delaney


Peter Hansen

unread,
May 30, 2002, 10:04:18 PM5/30/02
to
"Delaney, Timothy" wrote:
>
> > From: Skip Montanaro [mailto:sk...@pobox.com]
> > rows = self.executesql("select cities.city, state, country"
> > " from cities, venues, events, addresses"
> > " where cities.city like %s"
> > " and events.active = 1"
[snip]
>
> Just wondering Skip ... why would you write this rather than a triple-quoted
> string?
>
> rows = self.executesql("""
> select cities.city, state, country
> from cities, venues, events, addresses
> where cities.city like %s
> and events.active = 1
> and venues.address = addresses.id
> and addresses.city = cities.id
> and events.venue = venues.id
> """, (city,))
>
> which to me looks much cleaner and is much easier to modify.

And which has both embedded "\n" newlines and many more leading
spaces before each line...

-Peter

Delaney, Timothy

unread,
May 30, 2002, 10:10:40 PM5/30/02
to
> From: Peter Hansen [mailto:pe...@engcorp.com]

>
> And which has both embedded "\n" newlines and many more leading
> spaces before each line...

That's why I would bind it to a name first - that allows me to preprocess
the query before passing it in.

I would much rather write it so it is readable, then process it for the
database, than the other way around.

sql = """


select cities.city, state, country
from cities, venues, events, addresses
where cities.city like %s
and events.active = 1
and venues.address = addresses.id
and addresses.city = cities.id
and events.venue = venues.id
"""

sql = string.split(sql)
sql = string.join(sql, ' ')
sql = string.strip(sql)

rows = self.executesql(sql, (city,))

Skip also asked why I would bind the statement to a name. For a query of
this size, I find it easier to read - the sql query is separate and (to my
eye) cleaner than having the literal as a function parameter. Plus it uses
much less horizontal white space.

Tim Delaney


Skip Montanaro

unread,
May 30, 2002, 10:04:23 PM5/30/02
to

>> rows = self.executesql("select cities.city, state, country"

>> " from cities, venues, events, addresses"
>> " where cities.city like %s"
>> " and events.active = 1"
>> " and venues.address = addresses.id"
>> " and addresses.city = cities.id"
>> " and events.venue = venues.id",
>> (city,))

Tim> Just wondering Skip ... why would you write this rather than a
Tim> triple-quoted string?

Habit.

Tim> Of course, I also would have bound the SQL to a name first ...

Doesn't make sense to me. Each sql statement is substantially different
from all the rest and is only single use. The particular file I pulled that
out of contains 118 calls to the executesql method, 98 of which use string
literals for the SQL statement.

Tim> I've yet to find a place where I've had a use for concatenating
Tim> string literals.

To each his own.

Skip


Peter Hansen

unread,
May 30, 2002, 11:46:10 PM5/30/02
to
"Delaney, Timothy" wrote:
>
> > From: Peter Hansen [mailto:pe...@engcorp.com]
> >
> > And which has both embedded "\n" newlines and many more leading
> > spaces before each line...
>
> That's why I would bind it to a name first - that allows me to preprocess
> the query before passing it in.

> I would much rather write it so it is readable, then process it for the
> database, than the other way around.
>
> sql = """
> select cities.city, state, country
> from cities, venues, events, addresses
> where cities.city like %s
> and events.active = 1
> and venues.address = addresses.id
> and addresses.city = cities.id
> and events.venue = venues.id
> """
>
> sql = string.split(sql)
> sql = string.join(sql, ' ')
> sql = string.strip(sql)
>
> rows = self.executesql(sql, (city,))

What a lot of extra work to make something "readable"!
I don't think that this is more readable than the simple, straightforward
approach Skip presented. It uses many more lines and a bunch of
superfluous operations (without even a comment explaining why
you are splitting and joining things this way instead of just using
simple string concatenation).

If I saw code like this in my team I'd ask that a comment be
added to explain it, and if the comment said "# doing this so the
code is more readable" I'd ask that it be refactored so it didn't
need the comment at all, after I got back up off the floor.
I expect the refactoring would take the form of the original
example which needs no extra operations or commenting.

> Skip also asked why I would bind the statement to a name. For a query of
> this size, I find it easier to read - the sql query is separate and (to my
> eye) cleaner than having the literal as a function parameter. Plus it uses
> much less horizontal white space.

Nothing wrong with separating things out like that if you think it
looks more readable, but this is one case where I agree with Skip's
approach even though it looks a lot like "hardcoded strings" which
is generally a Code Smell. Simpler is much better here.

(I might agree with you more if I thought that maintaining the
string-concatenated version would actually be harder. Given the
likely nature of the maintenance -- adding fields to the line with
"from cities, ..." for example, or adding a new line to the
"where" intersection -- I don't believe it would be *any* harder.)

-Peter

Duncan Booth

unread,
May 31, 2002, 4:07:16 AM5/31/02
to
Chris Liechti <clie...@gmx.net> wrote in
news:Xns921EEEC6D92A...@62.2.16.82:

> i think the example is in the docs. e.g. when you want to comment on a
> complicated string, like an regex:
>
> re.compile("([ab])+" #group one (at least one occurence of either a
> or b)
> "(hello)*" #group two (optional)
> )

In this case you could also put the comments inside a single string which
may or may not make it more readable:

r = re.compile('''


([ab])+ #group one (at least one occurence of either a or b)

(hello)* #group two (optional)''',
re.VERBOSE)


--
Duncan Booth dun...@rcp.co.uk
int month(char *p){return(124864/((p[0]+p[1]-p[2]&0x1f)+1)%12)["\5\x8\3"
"\6\7\xb\1\x9\xa\2\0\4"];} // Who said my code was obscure?

Grant Griffin

unread,
May 31, 2002, 10:49:30 AM5/31/02
to
In article <yvwJ8.9951$p56.2...@newsb.telia.net>, "Fredrik says...

>
>Grant Griffin wrote:
>>
>> I discovered today that strings can sometimes be concatenated
>> without using a "+":
>
>had you read the language reference, you might have discovered
>this long ago:
>
> 2.4.2 String literal concatenation
> http://www.python.org/doc/current/ref/string-catenation.html
>

Whyever would I read the language reference?--that would deny you the pleasure
of spanking, and me the pleasure of getting spanked <wink>.

sadists-and-masochists-have-a-symbiotic-relationship-ly y'rs,

=g2

_________________________________________________________________________

Grant R. Griffin g...@dspguru.com
Publisher of dspGuru http://www.dspguru.com
Iowegian International Corporation http://www.iowegian.com

Grant Griffin

unread,
May 31, 2002, 11:21:11 AM5/31/02
to
In article <mailman.102279124...@python.org>, Skip says...

>
>
> Grant> I discovered today that strings can sometimes be concatenated
> Grant> without using a "+":
>
>Actually, string literals can always be concatenated without adding them.
>
> Grant> I discovered this, of course, while making a mistake like this:
>
> >>> a = ['zero', 'one'
> ... 'two', 'three']
> >>> a
> ['zero', 'onetwo', 'three']
>
>Yup, that's just how it's supposed to work. It makes it easier to compose
>long strings. For example, I have code like this that queries a database:
>
> rows = self.executesql("select cities.city, state, country"
> " from cities, venues, events, addresses"
> " where cities.city like %s"
> " and events.active = 1"
> " and venues.address = addresses.id"
> " and addresses.city = cities.id"
> " and events.venue = venues.id",
> (city,))
>
>At compile time all those strings are concatenated into one long string.
>The select statement remains readable for me, but is represented as a single
>string constant in the generated bytecode.

I guess I don't see what's so bad about having to put a "+" at the end of
each--except maybe that it brings on the need for a continuation backslash:

rows = self.executesql("select cities.city, state, country" +\
" from cities, venues, events, addresses" +\
" where cities.city like %s" +\
" and events.active = 1" +\
" and venues.address = addresses.id" +\
" and addresses.city = cities.id" +\


" and events.venue = venues.id",
(city,))

Sure, it's a little more typing, but one could argue that its easier to read
because it's explicit. (My non-SQL-trained eye would have initially read the
original as a series of parameters separated by commas which, upon closer
inspection, would be found not to actually be there.)

Better yet would be if the parser would automatically concatenate incomplete
expressions (as identified by a line that ends with an operator), much as it
automatically concatenates incomplete list and dictionary initialization
statements. Then your example would become:

rows = self.executesql("select cities.city, state, country" +
" from cities, venues, events, addresses" +
" where cities.city like %s" +
" and events.active = 1" +
" and venues.address = addresses.id" +
" and addresses.city = cities.id" +


" and events.venue = venues.id",
(city,))

which doesn't look so bad. (But then again, without the backslash it's less
explicit <wink>.)

explict-is-better-than-implicit-for-a-reason-ly y'rs,

Skip Montanaro

unread,
May 31, 2002, 12:10:23 PM5/31/02
to

Grant> rows = self.executesql("select cities.city, state, country" +
Grant> " from cities, venues, events, addresses" +
Grant> " where cities.city like %s" +
Grant> " and events.active = 1" +
Grant> " and venues.address = addresses.id" +
Grant> " and addresses.city = cities.id" +
Grant> " and events.venue = venues.id",
Grant> (city,))

Grant> which doesn't look so bad. (But then again, without the
Grant> backslash it's less explicit <wink>.)

You can avoid the backslash with a pair of parens. Recasting my original
example a little:

rows = self.executesql(("select cities.city, state, country" +


" from cities, venues, events, addresses" +
" where cities.city like %s" +
" and events.active = 1" +
" and venues.address = addresses.id" +
" and addresses.city = cities.id" +

" and events.venue = venues.id"),
(city,))

I'm surprised nobody commented on the rather weird indentation of the SQL
statement in my original example. I use the style in this last example now
(well, without the extra parens and the plus signs).

Steven Majewski

unread,
May 31, 2002, 12:12:01 PM5/31/02
to

On 31 May 2002, Grant Griffin wrote:

> Better yet would be if the parser would automatically concatenate incomplete
> expressions (as identified by a line that ends with an operator), much as it
> automatically concatenates incomplete list and dictionary initialization
> statements. Then your example would become:
>
> rows = self.executesql("select cities.city, state, country" +
> " from cities, venues, events, addresses" +
> " where cities.city like %s" +
> " and events.active = 1" +
> " and venues.address = addresses.id" +
> " and addresses.city = cities.id" +
> " and events.venue = venues.id",
> (city,))
>
> which doesn't look so bad. (But then again, without the backslash it's less
> explicit <wink>.)

The above *ought* to work.
The hanging "+" alone doesn't do the trick, but the hanging "(" does --
the parser knows it needs a matching ")" :

>>> ( "one" +
... "two" +
... "three" )
'onetwothree'


( Of course, it will work with the parends but *without* the "+" too! )

-- Steve Majewski


Terry Reedy

unread,
May 31, 2002, 1:03:21 PM5/31/02
to

"Grant Griffin" <Grant_...@newsguy.com> wrote in message

> In article <mailman.102279124...@python.org>, Skip
says...

> >At compile time all those strings are concatenated into one long
string.

> I guess I don't see what's so bad about having to put a "+" at the


end of
> each--except maybe that it brings on the need for a continuation
backslash:

Reread 'at compile time' (hopefully with linear algorithm) - only one
string object created.
+ works at runtime with n string objects in n*n time, possibly
repeatedly (if strings are in loop or function called more than once.
Quite aside from extra chars.

Terry J. Reedy

Rich Harkins

unread,
May 31, 2002, 12:39:07 PM5/31/02
to
On Friday 31 May 2002 11:21 am, Grant Griffin wrote:
> In article <mailman.102279124...@python.org>, Skip says...
>
> [ cool string concatenation method snipped ]

Here's why I personally like this:

>>>> '%s' 'x' % (5)
'5x'
>>> '%s' + 'x' % (5)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: not all arguments converted

Using this form of concatenation instead of the + form allows for the %
sprintf operator to work correctly. Joy!

Rich

Skip Montanaro

unread,
May 31, 2002, 12:47:30 PM5/31/02
to

Steve> The above *ought* to work. The hanging "+" alone doesn't do the
Steve> trick, but the hanging "(" does -- the parser knows it needs a
Steve> matching ")" :

Ah, yes. Ignore my previous post then with the extra (...)

Skip


Grant Griffin

unread,
May 31, 2002, 2:01:11 PM5/31/02
to
In article <s1OJ8.16485$4i.19...@bin2.nnrp.aus1.giganews.com>, "Terry says...

Yeah, I'd thought of that, but didn't bring it up because it goes against my
argument <wink>. Besides, I wasn't for sure if that was a compile-time thing or
a run-time thing.

In any event this thing seems rather un-Pythonic inasmuch as it violates
four--count 'em: four!--of Tim's design principles:

1) Explicit is better than implicit. (There's an implicit "+" here.)
2) Errors should never pass silently. (I discovered this construct via a silent
error I had made: omitting a comma resulted in one fewer string than I needed.)
3) There should be one--and preferably only one--obvious way to do it. (There
are two ways to concatenate string literals. But in all fairness, the second
one isn't all that obvious <wink>.)
4) Special cases aren't special enough to break the rules. (One can't
concatenate two string variables without the aid of a "+", so string _literals_
are a special case.)

Then again, as Tim himself once said, the key to any successful philosophy is to
have enough wiggle room to do what you wanted to do anyway. In that vein, I
suppose one could argue in favor of this that:

1) Beautiful is better than ugly. (Yes, the trialing "+"'s are a bit ugly,
especially when you add backslashes or extra parens.)
2) Simple is better than complex. (Yes, there's less typing. Still, folks who
obsessively conserve typing should be sentenced to a year of Perl--without
parole <wink>.)
3) Although practicality beats purity. (Yes, as Skip illustrates, this has its
practical uses--though I can't think of any others offhand <wink>.)

not to mention:

4) Namespaces are one honking great idea -- let's do more of those! (I don't
really know how namespaces come into this, but I just like the word "honking".)

a-proud-member-of-all-the-people-who-can't-be-pleased-all-the-time-ly y'rs,

Grant Griffin

unread,
May 31, 2002, 2:09:58 PM5/31/02
to
In article <mailman.1022861511...@python.org>, Skip says...
>
...

>You can avoid the backslash with a pair of parens. Recasting my original
>example a little:
...

Thanks, I didn't know that! (I really gotta take time to read the language
reference some day <wink>.)

> rows = self.executesql(("select cities.city, state, country" +
> " from cities, venues, events, addresses" +
> " where cities.city like %s" +
> " and events.active = 1" +
> " and venues.address = addresses.id" +
> " and addresses.city = cities.id" +
> " and events.venue = venues.id"),
> (city,))
>
>I'm surprised nobody commented on the rather weird indentation of the SQL
>statement in my original example. I use the style in this last example now
>(well, without the extra parens and the plus signs).

I dunno...I don't know anything about SQL, but your code looks sortta Pythonic.

this-whole-nutty-indentation-thing-is-starting-to-catch-on-ly y'rs,

Grant Griffin

unread,
May 31, 2002, 2:26:00 PM5/31/02
to
In article <mailman.102286331...@python.org>, Rich says...
>
...

>Here's why I personally like this:
>
>>>>> '%s' 'x' % (5)
>'5x'

>>>> '%s' + 'x' % (5)
>Traceback (most recent call last):
> File "<stdin>", line 1, in ?
>TypeError: not all arguments converted

So it looks like the implicit "+" operator has a higher precedence than the
explicit "+" operator. (BTW, who knew that a language that doesn't have "++"
would need two string concatenation operators?)

Perhaps that was just an example, but what was so bad about?:

>>> '%sx' % (5,) # don't hesitate to add trailing "," here <wink>
'5x'

or even?:

>>> ('%s' + 'x') % (5,)
'5x'

the-only-thing-worse-than-using-explicit-operators-is
-explicitly-specifying-their-order-<wink>-ly y'rs,

Skip Montanaro

unread,
May 31, 2002, 3:43:46 PM5/31/02
to
>> rows = self.executesql(("select cities.city, state, country" +
>> " from cities, venues, events, addresses" +
>> " where cities.city like %s" +
>> " and events.active = 1" +
>> " and venues.address = addresses.id" +
>> " and addresses.city = cities.id" +
>> " and events.venue = venues.id"),
>> (city,))

Grant> I dunno...I don't know anything about SQL, but your code looks
Grant> sortta Pythonic.

Yeah it does. It serves two purposes. One it makes it clear to me where
the various clauses of the select statement begin ("from ...", "where ...").
It also guarantees I have at least one space between the different
fragments. This:

("select cities.city, state, country"


"from cities, venues, events, addresses"

"where cities.city like %s"
"and events.active = 1"
"and venues.address = addresses.id"
"and addresses.city = cities.id"

"and events.venue = venues.id")

might appear correct, but there are no spaces between the end of one
substring and the start of the next...

Skip Montanaro

unread,
May 31, 2002, 3:50:26 PM5/31/02
to

'%s' 'x' % (5)

vs.

'%s' + 'x' % (5)

Grant> So it looks like the implicit "+" operator has a higher
Grant> precedence than the explicit "+" operator.

Minor semantic point here. Since the string concatenation is performed by
the compiler, not at runtime, it's probably not correct to call the first
form an implicit "+" operator. Nothing happens at runtime to squash the two
strings together. If you inspect the code object you can see this:

>>> def f():
... '%s' 'x' % (5,)
...
>>> f.func_code.co_consts
(None, '%sx', 5)

Skip


Daniel Fackrell

unread,
May 31, 2002, 3:12:10 PM5/31/02
to
"Grant Griffin" <Grant_...@newsguy.com> wrote in message
news:ad8f7...@drn.newsguy.com...

> In article <mailman.102286331...@python.org>, Rich says...
> >
> ...
> >Here's why I personally like this:
> >
> >>>>> '%s' 'x' % (5)
> >'5x'
>
> >>>> '%s' + 'x' % (5)
> >Traceback (most recent call last):
> > File "<stdin>", line 1, in ?
> >TypeError: not all arguments converted
>
> So it looks like the implicit "+" operator has a higher precedence than
the
> explicit "+" operator. (BTW, who knew that a language that doesn't have
"++"
> would need two string concatenation operators?)

This concatenation has nothing to do with operators. Operators are acted on
at runtime, this is simply a feature of the parser.

If I knew more about the bytecode that Python generates, I could go in and
show you that:

'a' 'b'

or

'a' # intra-string comment
'b' # post-string comment

produce bytecode for 'ab' (one token), where:

'a' + 'b'

is read in as three distinct tokens representing "'a'", "+", and "'b'". The
bytecode for this probably looks equivalent to operator.__add__('a', 'b') or
something similar.

I'm probably way off on the particulars, as I've not delved into the parser
at all, but this should give you the idea that this is a compile-time vs.
run-time difference, and has nothing to do with operators or operator
precedence.

Hope this helps.

Daniel Fackrell


Tim Roberts

unread,
Jun 1, 2002, 1:23:49 AM6/1/02
to
Grant Griffin <Grant_...@newsguy.com> wrote:
>
>I discovered today that strings can sometimes be concatenated without using a
>"+":
>
> ActivePython 2.2.1 Build 222 (ActiveState Corp.) based on
> Python 2.2.1 (#34, Apr 15 2002, 09:51:39) [MSC 32 bit (Intel)] on win32
> Type "help", "copyright", "credits" or "license" for more information.
> >>> a = 'one' ' plus ' 'two'
> >>> a
> 'one plus two'

It is interesting (but only marginally relevant) to note that this exact
same feature is part of ISO standard C:

#include <stdio.h>
int main()
{
puts( "one" " plus " "two" );
}
--
- Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.

Steve Holden

unread,
Jun 2, 2002, 2:08:41 PM6/2/02
to
"Skip Montanaro" <sk...@pobox.com> wrote in message
news:mailman.1022874291...@python.org...
I would personally much prefer to see this written as

("""select cities.city, state, country
from cities, venues, events, addresses
where cities.city like %s
and events.active = 1
and venues.address = addresses.id
and addresses.city = cities.id

and events.venue = venues.id""",
(city,))

Perhaps the reason that Python's conventional wisdom states "there should be
oine obvious way to do it" is because, given alternatives, people like you
and me will spend endless time debating which is to be preferred!

regards
Steve
--
-----------------------------------------------------------------------
Steve Holden http://www.holdenweb.com/
Python Web Programming http://pydish.holdenweb.com/pwp/
-----------------------------------------------------------------------

Steve Holden

unread,
Jun 5, 2002, 8:35:34 AM6/5/02
to
"Peter Hansen" <pe...@engcorp.com> wrote in message
news:3CF6F202...@engcorp.com...

> "Delaney, Timothy" wrote:
> >
> > > From: Peter Hansen [mailto:pe...@engcorp.com]
> > >
> > > And which has both embedded "\n" newlines and many more leading
> > > spaces before each line...
> >
> > That's why I would bind it to a name first - that allows me to
preprocess
> > the query before passing it in.
>
> > I would much rather write it so it is readable, then process it for the
> > database, than the other way around.
> >
> > sql = """
> > select cities.city, state, country
> > from cities, venues, events, addresses
> > where cities.city like %s
> > and events.active = 1
> > and venues.address = addresses.id
> > and addresses.city = cities.id
> > and events.venue = venues.id
> > """
> >
# The next three lines are bogus

> > sql = string.split(sql)
> > sql = string.join(sql, ' ')
> > sql = string.strip(sql)
> >
> > rows = self.executesql(sql, (city,))
>
> What a lot of extra work to make something "readable"!
> I don't think that this is more readable than the simple, straightforward
> approach Skip presented. It uses many more lines and a bunch of
> superfluous operations (without even a comment explaining why
> you are splitting and joining things this way instead of just using
> simple string concatenation).
>
Not only that, but for any reasonable database the whole schemozzle is
completely unnecessary. SQL is a free-format language, and newlines and
spaces embedded in statements make absolutely no difference.

> If I saw code like this in my team I'd ask that a comment be
> added to explain it, and if the comment said "# doing this so the
> code is more readable" I'd ask that it be refactored so it didn't
> need the comment at all, after I got back up off the floor.
> I expect the refactoring would take the form of the original
> example which needs no extra operations or commenting.
>

Or simply remove the three bogus lines and leave the SQL as it's generated.

> > Skip also asked why I would bind the statement to a name. For a query of
> > this size, I find it easier to read - the sql query is separate and (to
my
> > eye) cleaner than having the literal as a function parameter. Plus it
uses
> > much less horizontal white space.

I hadn't realised there was a shortage :-) [Seriously, I like the embedded
newline style, as I underline below...]


>
> Nothing wrong with separating things out like that if you think it
> looks more readable, but this is one case where I agree with Skip's
> approach even though it looks a lot like "hardcoded strings" which
> is generally a Code Smell. Simpler is much better here.
>
> (I might agree with you more if I thought that maintaining the
> string-concatenated version would actually be harder. Given the
> likely nature of the maintenance -- adding fields to the line with
> "from cities, ..." for example, or adding a new line to the
> "where" intersection -- I don't believe it would be *any* harder.)

As I said earlierrr, in another post: '''would personally much prefer to see
this written as

("""select cities.city, state, country


from cities, venues, events, addresses
where cities.city like %s
and events.active = 1
and venues.address = addresses.id
and addresses.city = cities.id

and events.venue = venues.id""",
(city,))
'''

but it's largely a matter opf taate. What clealy *should* be avoided is
unnecessary programmed transformation of SQL statements.

Delaney, Timothy

unread,
Jun 5, 2002, 7:41:37 PM6/5/02
to
> From: Steve Holden [mailto:sho...@holdenweb.com]

>
> # The next three lines are bogus
> > > sql = string.split(sql)
> > > sql = string.join(sql, ' ')
> > > sql = string.strip(sql)
> > >
> > > rows = self.executesql(sql, (city,))
>
> Not only that, but for any reasonable database the whole schemozzle is
> completely unnecessary. SQL is a free-format language, and
> newlines and
> spaces embedded in statements make absolutely no difference.

I agree entirely - if you can rely on the database to handle embedded
newlines in queries (and most can) then there is no need to perform the
preprocessing.

I meant to include that those lines were only there to match the original,
which did not have embedded newlines.

The main point is the preference to use a triple-quoted string to lay out
the query readably. If preprocessing is necessary, I would *still* prefer
that, and add the required preprocessing.

After all, SQL queries are often read in from files, with newlines in the
queries ...

Tim Delaney


0 new messages