views:

471

answers:

4

So according to the Zen of Python ... Explicit is better than implicit...Sparse is better than dense...Readability counts...but then again Flat is better than nested...so then which is pythonic?

val = "which is pythonic?"
print("".join(reversed(val)))

or

print(val[::-1])

I'm just a Java programmer learning Python so I find this pythonic stuff interesting since there is no analog in the Java world AFAIK.

+4  A: 

The second one (in my opinion) is more Pythonic as it is simpler, shorter, and clearer.

For more info on what is Pythonic I would recommend The Zen of Python:

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

In my opinion your second example satisfies these tenets:

Beautiful is better than ugly.
Simple is better than complex.
Sparse is better than dense.
Readability counts.

Andrew Hare
Interesting you recommended the Zen when he put it in his question.
Jed Smith
Whoops - you are right - I didn't even see that :) I guess that was pretty Zen of me as well.
Andrew Hare
A: 

With a string, as you have, I would go with the first option, since it makes it clear that the result you want is a string. For a list or other iterable/slicable, I'd go with the second.

An added benefit of the first form is it will work if val is not actually a string, but some other iterable of characters (e.g. a generator of some kind). In some cases, this makes a big difference.

Daniel Pryden
@Daniel isn't a string also considered a sliceable/iterable as well?
non sequitor
@Daniel The first form actually does *not* work for an iterable: reversed() works with a *sequence*. In particular, the object needs a to have a length (i.e. a __len__ method). You can try reversed(itertools.repeat(1)), for instance: it raises a TypeError.
EOL
@EOL: Ah yes, you're right. Well, I guess that makes my point moot after all.
Daniel Pryden
+35  A: 

My wife Anna has nicknamed x[::-1] "the Martian Smiley" -- I mostly bow to her (and her long experience in training &c, and studies in human psychology &c), when it comes to judging what's easy and natural for most people, and she absolutely loves the martial smiley. "Just walk it backwards" -- how much more direct, and high-abstraction, than the detailed specification of "reverse it and then join it back"!

Also, python -mtimeit is often a good judge of what's Pythonic: top Pythonistas, over the years, have of course tended to optimize what they most often needed and used, so a very substantial performance difference tells you what "goes with the grain" of the language and its top practitioners. And by that score, the martian smiley beats the detailed spec hands-down...:

$ python -mtimeit '"".join(reversed("hello there!"))'
100000 loops, best of 3: 4.06 usec per loop
$ python -mtimeit '"hello there!"[::-1]'
1000000 loops, best of 3: 0.392 usec per loop

order-of-magnitude performance differences just don't leave that much room for doubt!-)

Alex Martelli
+1, Interesting.
Edmund
I dunno... I've used Python quite a bit for several years now, and I still find slice syntax one of the most cognitively difficult aspects of Python. (I find generator comprehensions much easier to read, for example.) But there's really no arguing with an order of magnitude speed increase, so I guess this really is the best solution.
Daniel Pryden
Jed Smith
Oh wow, I'm happy I asked this question, even the python coders are surprised -- thanks Alex.
non sequitor
what setup are you using ? i can't reproduce such a huge difference between the 2 statements. i tested python 2.6 and 3.1, and they have roughly the same execution time...
Adrien Plisson
@Adrien: I've tried it on Python 2.6 and 3.1 (Ubuntu). "the Martian Smiley" is 8 times faster.
J.F. Sebastian
@J.F.Sebastian:haa, i see it now, a problem with quote and double-quotes on Windows. the martian smiley is truly faster.
Adrien Plisson
A: 

First, if you are a beginner, don't worry what is more pythonic or not. This smell language wars, and you will eventually find your own opinion anyway. Just use the way you think is more readable/simpler for you and you will find the light, I think.

That said, I agree with Alex's excellent answer (as he is always right) and I would add an additional comment why you should prefer the second method - the first will only work correctly if val is a string.

J S
No, the first will work correctly with any iterable of strings (of which a string is a special-case iterable of one-character strings). On the other hand, the second will work with any slicable object (strings are one example, lists are another, but generic iterables won't work). While both work fine for the case where you're sure your input is a string, there may be edge cases where the semantic differences will catch you.
Daniel Pryden
Thanks @Daniel I'll keep that in mind
non sequitor