invert or reverse a string... warning this is a rant

Steven D'Aprano steve at REMOVE.THIS.cybersource.com.au
Thu Oct 19 19:04:07 EDT 2006


On Thu, 19 Oct 2006 12:38:55 -0400, Brad wrote:

> John Salerno wrote:
>> rick wrote:
>>> Why can't Python have a reverse() function/method like Ruby?
>> 
>> I'm not steeped enough in daily programming to argue that it isn't 
>> necessary, but my question is why do you need to reverse strings? Is it 
>> something that happens often enough to warrant a method for it?
> 
> I'm home for lunch so my email addy is different.
> 
> No, it doesn't happen very often, but when I need to reverse something 
> (usually a list or a string). I can never remember right of the top of 
> my head how to do so in Python. I always have to Google for an answer or 
> refer back to old code.
> 
> IMO, I should be able to intuitively know how to do this. Python is so 
> user-friendly most every place else... why can it not be so here?

I agree -- the reversed() function appears to be an obvious case of purity
overriding practicality :(

>>> str(reversed("some string"))
'<reversed object at 0xb7edca4c>'
>>> repr(reversed("some string"))
'<reversed object at 0xb7edca4c>'

Not very useful.

The simplest ways to get a reversed string seem to be:

>>> "some string"[::-1]
'gnirts emos'
>>> ''.join(list(reversed("some string")))
'gnirts emos'

neither of which are exactly intuitive, but both are standard Python
idioms.



> I wrote this so I'll never have to remember this again:
> 
> def invert(invertable_object):
>      try:
>          print invertable_object[::-1]
>          return invertable_object[::-1]
>      except:
>          print 'Object not invertable'
>          return 1

Gah!!! That's *awful* in so many ways.

(1) The name is bad. "invert" is not the same as "reverse". Here's an
invert: 1/2 = 0.5. Your function falsely claims numbers aren't invertable.

(2) Why calculate the reversed object twice?

(3) It is poor practice to have the same function both *print* the result
and *return* the result. What happens when you want the reversed object,
but you don't want it to print? You either write a new function, or you
muck about capturing output and hiding it. You should return the result,
and leave it up to the caller to print if they want to print.

(That's a complaint I have about the dis module -- it prints its results,
instead of returning them as a string. That makes it hard to capture the
output for further analysis.)

(4) Why are you capturing Python's perfectly good and useful traceback,
and printing an unhelpful error message?

(5) Errors should raise exceptions, not return "magic numbers" like 1. 1
is not an error-state, it is perfectly fine output. Now you have to
remember that your invert function returns 1 on error, and calling code
has to check for it:

list_of_reversed_object = []
for obj in list_of_objects_to_reverse:
    temp = invert(obj)
    if temp == 1:
        raise ValueError("invalid object")
        # or do something else...
    list_of_reversed_objects.append(temp)

Compare:

list_of_reversed_object = []
for obj in list_of_objects_to_reverse:
    list_of_reversed_objects.append(invert(obj))


Or if you want to skip invalid objects:

list_of_reversed_object = []
for obj in list_of_objects_to_reverse:
    try:
        list_of_reversed_objects.append(invert(obj))
    except SomeError:
        pass



-- 
Steven.




More information about the Python-list mailing list