MacUsers
MacUsers

Reputation: 2229

printing string with and without "Strings-Formatting"

I'm trying to find out why I'm seeing this. This is the code-snippet:

def check_status(addr,port=80):

    import urllib2

    if not addr.startswith('http://'): addr = "http://" + addr
    req = urllib2.Request(addr+":"+str(port))

    try:
        res = urllib2.urlopen(req,None,10)
        sts = str(res.code)

    except urllib2.URLError, er:
        sts = er.args

    print "Print-1\t: %s" % sts
    print "Print-2\t:", sts
    print "{0}\t: {1}".format('Print-3',sts)
    return sts


url = "google.comm"
sts = check_status(url)
print "Print-4\t: %s  %s" % (url, sts)

Running the script, I get interesting result on print statement:

Print-1 : [Errno 8] nodename nor servname provided, or not known
Print-2 : (gaierror(8, 'nodename nor servname provided, or not known'),)
Print-3 : (gaierror(8, 'nodename nor servname provided, or not known'),)
Print-4 : google.comm  (gaierror(8, 'nodename nor servname provided, or not known'),)

Can anyone please explain why printing sts coming differently for print-2, 3 and 4? It's printing in correct format only with single %s formatting-string. I don't think it's got anything to do with urllib2. What am I missing here? Thanks!

Upvotes: 0

Views: 203

Answers (1)

abarnert
abarnert

Reputation: 365915

Passing a single argument to % is ambiguous, so Python applies a rule that's confusing in some cases, but most often the answer you wanted. If the argument is not a tuple, it's treated as if it were wrapped in a 1-element tuple.

So this:

print "Print-1\t: %s" % sts

… prints str(sts[0]) if it's a 1-element tuple, and raises a TypeError if it's a tuple of any other length, but prints str(sts) if it's just a string (or an Exception or whatever).

All of your other examples:

print "Print-2\t:", sts
print "{0}\t: {1}".format('Print-3',sts)
print "Print-4\t: %s  %s" % (url, sts)

… just print str(sts), because they don't have this magic rule.

In your case, sts is a 1-element tuple. So, str(sts[0]) is what you want, because str(sts) is equivalent to '(' + repr(sts[0]) + ',)'. You got lucky with Print-1 because you hit the magic rule by accident. (You may not even have known that er.args was a tuple.)


This kind of confusion is exactly why people keep suggesting deprecating %-formatting, or changing it so it always treats its argument as a sequence, etc. But because it's so handy for so many quick&dirty purposes, those suggestions always get defeated.

One way to avoid confusing yourself is to always pass even a single argument as a tuple: print "Print-0\t: %s" % (sts,). Or just don't use %-formatting.

Upvotes: 2

Related Questions