Why do this?

M

Matthew Warren

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
 
D

Duncan Booth

Matthew Warren said:
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.
 
M

Marc 'BlackJack' Rintsch

Matthew Warren said:
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
 
I

Ivan Voras

Duncan said:
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)
 
M

Maric Michaud

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
 
C

Corrado Gioannini

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.
 
D

Dennis Lee Bieber

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
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
H

half.italian

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
 
D

Duncan Booth

Corrado Gioannini said:
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.
 
C

Corrado Gioannini

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)
 
L

Lawrence D'Oliveiro

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
 
F

Fredrik Lundh

Lawrence said:
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>
 
S

Steve Holden

Fredrik said:
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
 
D

Duncan Booth

Lawrence D'Oliveiro said:
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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top