Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I am learning Python and am intrigued by the following point in PEP 20 The Zen of Python:

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.

Could anyone offer any concrete examples of this maxim? I am particularly interested in the contrast to other languages such as Ruby. Part of the Ruby design philosophy (originating with Perl, I think?) is that multiple ways of doing it is A Good Thing. Can anyone offer some examples showing the pros and cons of each approach. Note, I'm not after an answer to which is better (which is probably too subjective to ever be answered), but rather an unbiased comparison of the two styles.

share|improve this question

4 Answers 4

up vote 41 down vote accepted

Compared to languages like Perl, Python has a limited number of control constructs:

  • only if and no unless,
  • only for that iterates over sequences and no foreach or C-style for,
  • only while that checks a condition every loop and no do-while,
  • only if-elif and no switch,
  • there's only one comment construct, the #, and for every line you can tell if it is commented out or not, without looking at previous lines.

Also, there's nearly one way to indent your source; most cases of creative indentation are syntactically excluded.

This makes parsing a Python source easier for humans.

There are attempts to be minimal-but-complete in built-in types and the standard library.

  • for mutable list you use the only built-in list type; it's O(1) for most operations, and you never have to choose the right implementation,
  • for immutable lists, equally, you just use the tuple type,
  • for maps, you use the only built-in dict which is damn efficient in most cases, no need to ponder which implementation to use.

Python 3 extends this to integers: no matter how big your integer is, you use the same type and never care about coercion.

Python tries to avoid syntactic sugar. But sometimes it adds syntactic sugar just to make the obvious way obvious. You can write if foo is not None instead of if not (foo is None) because 'is not' is special-cased. Still foo is not None reads easily, can't be misinterpreted, and you don't have to think, you just write the obvious thing.

Of course, most of more complex things in Python can be done in several ways. You can add methods to classes by declaration or by simple slot assignment, you can pass arguments to functions in a number of creative ways, etc. That's just because the internals of the language are mostly exposed.

The key is that there's always one way which is intended to be the best, the cover-all case. If other ways exist, they were not added as equal alternatives (like if and unless) but merely expose the inner workings. Slowly but steadily such alternatives are obsoleted (not eliminated!) by enhancing the known best mechanism.

Decorators wrap AOP function calls. Before 2.6 you had to use __metaclass__ magic member to declare a class's metaclass; now you can use the same decorator syntax for this, too. Prior to 3.0 you had two sorts of strings, byte-oriented and Unicode, which you could inadvertently mix. Now you have the only Unicode str and the only binary-transparent bytes, which you can't mix by mistake.

share|improve this answer
3  
Just as a note, don't forget """ comments (docstrings). These span multiple lines. –  syrion Jul 27 '11 at 20:08
8  
Triple-quoted literals are just strings, the same as single-quoted, but can span multiple lines without escaping line ends. A string literal right after declaration is considered a doc string, and it's not a comment, it's usually accessible as __doc__ attribute. But strings is an area where Python definitely provides many 'right ways': use single, double, or triple quote, implicitly join adjacent literals, use r for raw literals, etc. –  9000 Jul 27 '11 at 21:29
1  
I think @syrion's comment was regarding the "you can always decide whether a line is commented or not by just looking at it", which is not true because of """ strings. –  blubb Aug 1 '11 at 18:25
2  
"This makes parsing a Python source easier for humans." <- that's subjective –  jiggy Aug 1 '11 at 19:51
    
How did the metaclass declaration change in 2.7? Can't find the decorator pattern in the 2.7 docs for metaclasses. –  Nick T Sep 3 '13 at 7:20

Another couple of examples are:
len() is a function instead of a method present in every sequence; if you compare with Java you have .length(), .size, and other methods to find the number of elements in a sequence.

Another example is the fact that .join() is a string method, not a method present in every sequence. You don't need to know if the join parameter is a list, a set, a comprehension, or whatever, it will work.

share|improve this answer

In C there are many possible ways to increase the value of a variable by one:

i++     // Post-increment, returns the number before the increment
++i     // Pre-increment, returns the number after the increment
i += 1 

Each ends up increasing the value of i by 1, but each is slightly different.

In Python, there's really only one way; just add one.

i += 1

And while there's more than one syntactically valid way to do this (e.g. i = i + 1), you're doing the same thing with the same side effects.

share|improve this answer
1  
I'm no expert, but that example seems to precisely violate the "only one way to do it" idea. We have two ways to do it, but which is the more obvious? To my eyes the first example is more obvious while the second is a little more terse but no less readable or obvious to any programmer who has progressed beyond the very basics. Thank you for your answer - it's good food for thought. –  Charles Roper Jul 27 '11 at 18:34
    
@Peter (and @Charles): Actually, i = i + 1 is assignment, not an increment. In python an increment is i += 1. In C-style languages you can write i++, ++i, and i += 1. –  Josh K Jul 27 '11 at 18:56
2  
Not sure about your "lot of confusion" comment, all three of your C examples (you missed i += 1, BTW) produce exactly the same result. The only time I see people getting confused is when they pre- or post-increment a variable as part of a larger expression, and that's usually quickly rectified by reading the appropriate section of the language reference. Personally, I'd have picked on the fact that you can refer to the fifth character of a string by both str[4] or *(str+4), but maybe that was too easy... –  TMN Jul 27 '11 at 19:18
1  
@TMN: some cases, like max(i++, ++i) can't be quickly rectified. C has a lot of "undefined" and "implementation-dependent" behavior cases, all for a good reason — but each can create a pitfall. –  9000 Jul 27 '11 at 21:33
    
@TMN: Not to mention 4[str] (valid in C, may not be valid in C++). –  Vatine Jul 28 '11 at 11:52

Another possibility might be list comprehensions. In Python, you could do this:

new_list = []
    for item in list_of_items:
       if item < 10:
           new_list.append(item)

But the "obvious" way (if you're Dutch or are more familiar with Python) of doing this would be with a list comprehension:

new_list = [item for item in list_of_items if item < 10]

It's shorter, the new_list is created in one step, it runs faster I believe, and it is elegant. On the downside, one could argue it feels less explicit, but I think once you get used to it, it is just as explicit.

share|improve this answer
    
For indentation and code: prepend it with 4 spaces, then it will respect indentation. –  Inca Aug 1 '11 at 17:33

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.