Like in any other discipline, building software is in many cases, a matter of tastes. Depending on the developer background and the experiences it has, the code produced would be different in many aspects, leading usually to a heterogeneous styles to resolve the same problems using code.
In order to have some rules to have kind of similar code in Python when developers are trying to resolve the same kind of issues, it was written the Zen of Python, that is a set of rules to help developers to decide how to write code as a proper Pythonista.
- 1 Rules of the Zen of Python
- 1.1 Beautiful is better than ugly
- 1.2 Explicit is better than implicit
- 1.3 Simple is better than complex
- 1.4 Complex is better than complicated
- 1.5 Flat is better than nested
- 1.6 Sparse is better than dense
- 1.7 Readability counts
- 1.8 Special cases aren’t special enough to break the rules
- 1.9 Although practicality beats purity
- 1.10 Errors should never pass silently
- 1.11 Unless explicitly silenced
- 1.12 In the face of ambiguity, refuse the temptation to guess
- 1.13 There should be one– and preferably only one –obvious way to do it
- 1.14 Although that way may not be obvious at first unless you’re Dutch
- 1.15 Now is better than never
- 1.16 Although never is often better than right now
- 1.17 If the implementation is hard to explain, it’s a bad idea
- 1.18 If the implementation is easy to explain, it may be a good idea
- 1.19 Namespaces are one honking great idea — let’s do more of those!
- 2 Why the Zen of Python?
- 3 Recommended books to learn Python
Rules of the Zen of Python
There are only 19 rules to build code in Python and to unify the criteria on which decisions should be taken in case of doubts. The rules are written into the PEP 20 and can be found here: https://www.python.org/dev/peps/pep-0020/ but on this post you will find them and examples of how to apply them.
Every Python interpreter has an easy way to pull the zen of Python, just typing
>>> import this """ The Zen of Python, by Tim Peters 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! """
Beautiful is better than ugly
Even if usually the beautiful or ugliness of a something is subjective, when reading code, usually we use expressions like it stinks or doesn’t look right, that are similar to say that code is ugly.
So it is recommended that every time you read Python, you have the feeling that the code is beautiful, otherwise try to rewrite it in a more beautiful way.
cats = 4 dogs = 6 legs = 40 assert legs == (cats * 4) + (dogs * 4)
The sense of beauty on the code is trained over the experience so it is normal to get that sense over the time.
Explicit is better than implicit
The explicit code is the one that doesn’t require some further understanding of the code behind what is shown on the code, it is clean, simple and more expresive that the implicit version.
Sometimes, convering implicit code into explicit code, is as simple as adding some proper names to the variables used on a function or a method.
def f(a, b): return math.sqrt(a**2 + b**2)
def pythagoras_theorem(a_side, b_side): hypotenuse = math.sqrt(a_side**2 + b_side**2) return hypotenuse
Simple is better than complex
The best approach to develop systems is to make small and simple part of the them. The simpler the better as they could be tested easier and get modulazed easily.
There is no issue on having complex systems if they are made of simple parts, well splitted and with a proper context on each individual parts.
Complex is better than complicated
As said on the previous rule, when a system is build on top of many simple and individual parts, it should become complex but never complicated.
The difference between complex and complicated is on the clarity and readability of each individual sub-system, so there must be a good trade off between each individual part of the system and the complexity that holds.
UPPER_LIMIT = 32 LOWER_LIMIT = 3 POSITION = 1 def eval_change(value): prev_pos = POSITION if value > ((UPPER_LIMIT + LOWER_LIMIT) * 5 / 4): new_pos = 1 elif value < ((LOWER_LIMIT + UPPER_LIMIT) * 2 / 4): new_pos = 0 return prev_pos != new_pos
def eval_change(value, current_value): should_change = False if current_value == 1: should_change = debe_apagar(valor) elif current_value == 0: should_change = should_turn_on(value) return should_change def should_turn_on(value, upper_val=UPPER_LIMIT, lower_val=LOWER_LIMIT): limit = upper_val + lower_val * 5 / 4 return value > limit def debe_apagar(valor, upper_val=UPPER_LIMIT, lower_val=LOWER_LIMIT): limit = upper_val + lower_val * 2 / 4 return value < limit
So the complexity and correct order would be (> means better than):
Simple > Complex > Complicated
Flat is better than nested
Reading complex, dense or nested code requires a lot of attention and after several hours of analyzing code, developing new features and killing some bugs, the retention of information of developers should be quite low.
This is why any rule that help readability helps a lot, and in this case it is quite simple and easy to apply rule, flat structure require less analysis focus and translate to better reading code.
Sparse is better than dense
This rule is aligned with the previous one and also helps the readability of the code. Quite often we can find code too dense that would take hours to decode and make an internal logical map to understand.
So it is better to create a sparse version of the code to help readability instead.
print(','.join(map(str, [x ** 2 for x in range(5)])))
a = [x ** 2 for x in range(5)] b = map(str, a) c = ','.join(b) print(c)
This rule is one of the simple and most important one. The code is written once but read many times, so readability counts and counts a lot more than the code, the logic or the feature itself.
When writing code, we need to take care on the readability, modularization and maintainability of the code we produce, otherwise, the next developer that read the code would be completely lost and potentially will require to re-write partially or totally the work we have done.
There are many rules that can be applied like the SOLID ones or the one included at Clean Code book that would help to create better code.
list_of_powers = [x ** 2 for x in range(5)] str_of_powers = map(str, list_of_powers) powers_formatted = ','.join(str_of_powers) print(powers_formatted)
Special cases aren’t special enough to break the rules
When there are rules, they must be followed, so there shouldn’t be special cases that break them. Usually the break of rules mean don’t follow good practises and increasing the technical debt.
Although practicality beats purity
Many times we study books of desing patterns, analize each algorithm and try to apply all the knowlege learn on the books to the code in order to make the most pure and destilated piece of art (code).
This kind of approach, usually, lead to spend too many hours over-engineering a solution that could have been done on a more practical manner in a fraction of the time spent, so it is much more important to find the balance between the purines and the practicality and apply the common sense when we are developing.
Errors should never pass silently
Errors and exceptions are great tool to have on the toolchain and to unchain the power of them the first rule must be that “Error should never pass silently”, because we can’t fix an error that we are not aware is present on the system.
The most common apply of this anti-pattern is found when using
try: except: pass
try: erroneus_code() except Exception: pass
Unless explicitly silenced
Following with the previous rule, there are certain particular occasions when, although we are doing a proper handling of the error, we explicitly want that error to be silenced.
For instance, imagine a situation where the error raised is a knwon one and that has some meaning on the application context, for instance a ValueError, but if there is a difference exception, it should be propagated.
This kind of logic can be implemented as follows:
try: potential_erroneous_code() except ValueError: logger.debug('ValueError handled correctly')
In the face of ambiguity, refuse the temptation to guess
When developing software applications, many times there are ambiguities raised by half specs, some hidden parts that are not well defined or directly features that are only half thought.
This kind of situations are usually solved, and even more on startups, directly by letting the developers to guess how should it be the implementation and likely this kind of solutions are bugs by definition, so it is in our hand to identify those potential flaws on the tasks and try to don’t guess ever, ask and clarify each part of the features we are developing.
There should be one– and preferably only one –obvious way to do it
This rule is one of the most powerful ones, many times when we try to tackle an issue, there could be different options that could be used to do it, but if there is a consensus on how to develop, we can create a far better programming language where in case of doubts there will be only one way to do the thing, and usually that way is the best one.
Although that way may not be obvious at first unless you’re Dutch
This rule follows the previous one, quite often the obvious solution to a problem doesn’t come up at the first glance, but it would require some more thought and work to find it out.
The part of the Dutch people is a wink to the benevolent dictator for life and creator of the Python language, Guido van Rossum who has Dutch nationality.
Now is better than never
This rule tries to enforce to do the tasks the sooner the better, trying to mitigate that the task would never been done if we keep posponing the task.
On the software development field, postponing a task usually lead to increase the technical debt, and that could kill any project if it is not handled correctly.
One common situation of postponing the tasks is when we are developing a system and trying to add the tests at the end of the development instead of adding them during each development (or sprint) phase. Sometimes is too late to do those tasks and it will be far more painful than doing them step by step.
Although never is often better than right now
The tasks to be tackled on a project should be planned and prepared with some time ahead. If we try to rush a task usually we are not as ready as if we have some time to think about it and tackle it properly.
So in this aspect, the planning phase of each project is as important and as helpful as the implementation phase, never do tasks in a rush, otherwise you are compromising the solution quality in order to increase the number of things “done”.
If the implementation is hard to explain, it’s a bad idea
The aplication of this rule is not only limited to the Computer Science or software development field, but to all the areas in the humans world.
When we are trying to know if an idea is good or bad, try to explain the idea to a random person, if it is hard to explain and easily can be seen potential problems… it is a bad idea.
If the implementation is easy to explain, it may be a good idea
This other rule is on contrast of the previous one, when we are talking about some idea and we can see that flow the parts of it and that is composed of simple small pieces that works as a one, you are like of been found a good idea!
Namespaces are one honking great idea — let’s do more of those!
Python has namesaces helping to module each part of the development and creation of packages.
It was a good idea to develop the feature and one of the key points that helps the ecosystem of Python a place where to develop programs is pleasant and simple, so let’s make sure that we are using them on a proper way.
Why the Zen of Python?
Python is a great programming language because of many features but some of them are the guides that are introduced by some PEPs.
The PEP 8 clarifies how to style your Python code and help to create more uniform and well done code and the PEP 20 helps to determinate how to write Pythonic code, raising the standard of the code to a high quality level.
When having some rules to write the code, the result of the packages, libraries and framework is awesome and all the code have a great look and feel and a simple way to develop each part. This is a feature that only few languages can brag off, and we are super lucky to have in Python!
Recommended books to learn Python
This is a list of recommended books to learn Python, how to program, data types, algorithms and much more.