Python Best Practices and Tips

February 3, 2016 | Fyez Ahmed (Editor)
featured

Python is a high-level language used in many developmental areas, like desktop UI (PyQT), data analysis (scikit-learn), system administration (OpenStack, Ansible) and web development (Flask, Django). What sets Python apart from others languages is its developmental speed. Python comes integrated with a clean syntax, a lot of 3rd party libraries along with its own rich standard library. All of these resources allow a developer to focus primarily on solving problems , rather than wrestling with an unresponsive language and other problematic language details.

Keep indentations similar in the same Python file

Indentation level is extremely important. Mixing spaces and tabs is not good proactively and is not recommended in the slightest. In fact, Python 3 will outright deny interpreting files that are mixed, while Python 2 tabs are interpreted as if they have been converted to spaces using 8-space tab stops. This means that when executing you will have no idea about which indentation level a specific line is being considered .

To avoid confusion you should stick to PEP-8, or a coding style that is team specific because you have no idea if somewhere down the line some other programmer will read or use your code and be utterly confused. PEP-8 is a good go-to because it strongly discourages mixing tabs and spaces within the same file.

1

The first down-side of mixing and matching is that it quickly becomes an undecipherable mess. Formatting should be the core responsibility of the IDE. Consider that developers have enough on their plate without having to worry about how many spaces an IDE will insert, the size of tabs etc. The code should be displayed correctly and the format should be on point without the developer being forced to decipher it.

Essentially you might want to consider doing away with tabs altogether. The semantics of tabs are not very well-defined as far as computers are concerned so they can be displayed in different ways on different systems and editors. Consider also that during cop-paste operations, tabs often get destroyed. The same can be seen when a piece of source code is inserted into a web-page or any other kind of markup code.

Don’t leave a ticking time-bomb behind

Just in order to get the job done and ship quickly automated tests are at times not written. This is very bad practice because eventually a bug will hit the surface and when this happens it will be on the production server, resulting in the customer’s downtime. The official source of the problem might be stated as an unrelated issue arising from a manually-tested new feature. But you know the truth. Maybe after many thousand cups of coffee the bug will even be weeded out but it will be too late at this point.

The consequences of something like this happening can be a completely and utter catastrophic and might result in the company losing millions of dollars. The company could very well be out of business because of this smallest of infractions.

2

This entire cluster-flub can easily be avoided if the developer gets into the practice of writing unit tests and doc tests. Another good rule of thumb is to run the tests across the entire project once a new feature has been implemented.

Not writing semi-obfuscated code along with comments is seen by many developers as a way to save time. Some think that if they avoid writing docstrings it’s one step closer to completing a project on time. No one ever has ever regretted not relying on personal memory right? Wrong. I promise you’ll kick yourself later when you don’t remember why you did a particular thing while programming, or where you were trying to end up when reading your own code.

The problem doesn’t end there. Later on, after you’ve left the company you will have left a disaster your in your wake. Members of your team will be left trying to decipher code that it seems only you are able to understand.

Writing proper documentation should be ingrained in your DNA. It does not take too much time at all to write a doc-strings and comments. This applies even more imperative if your piece of code is particularly complex.  Another way to not leave your colleagues in a lurch is to name your methods, variables and functions to reflect the intention of your component. In a way all of your work will be self-documented if your component’s elements are named. You can learn how to do it here: document your Python code.

THE EAFP Paradigm

Something that is hard to understand for some developers, especially developers that come from a background of writing c++ or Java is the usage of the try:except:else constructs. This code is very different in Python, and has been adopted in a manner that is much different than c+ or Java. In Python using the try:except:else construct is a good practice to use and is an integral part of Pythons core philosophies – the “EAFP paradigm” or “It’s easier to ask for forgiveness than permission.”

 

4

If you don’t use this construct it will result in a messy code that at it’s very core will be very ‘unpythonic”. Raymond Hetttinger, a core python developer shines a little light on this philosophy:

In the Python world, using exceptions for flow control is common and normal. Even the Python core developers use exceptions for flow-control and that style is heavily baked into the language (i.e. the iterator protocol uses StopIteration to signal loop termination). In addition, the try-except-style is used to prevent the race-conditions inherent in some of the “look-before-you-leap” constructs.

For example, testing os.path.exists results in information that may be out-of-date by the time you use it. Likewise, Queue.full returns information that may be stale. The try-except-else style will produce more reliable code in these cases. In some other languages, that rule reflects their cultural norms as reflected in their libraries. The “rule” is also based in-part on performance considerations for those languages.

Use Python Open-End Operands as your greatest ALLY

Boolean values, Python’s logical operations . Actual values are not returned just True or false the operation can be returned as well.

To speed up development and to increase code readability the power of the Python logic operands can be used. In the following example, object will be fetched from the cache, or it will be fetched from he database if it’s missed in he cache:

# check_in_cache returns object or None

def get_obj():

return check_in_cache() or pull_from_db()

In the provided example, it will firs try to get an object from the cache (check_in_cache() function). If a None is returned instead and an object is not returned, it will get it from the database (pull_from_db() function). This is way better than the following snippet code which is how you would go about to execute the same function in the standard way:

def get_obj():

result = check_in_cache()

if result is None:

result = pull_from_db()

return result

The difference is pretty much evident. One lime ofcode is written instead of four and the prolem is solved in either cases. Aside from this the first example of code is much more readable and expressive.

One thing to be mindful of – there should be an awareness of returning objects with logical equivalent of False. An empty list is an example of this. If check_in_cache()  function returns such an object, it will be treaed as missing, and will cause your app to call a pull_from_db function. In an event such as this, where your function could be returning these kin of objects you might want to consider using additional unit is None check.

 

Leave a Reply

Your email address will not be published. Required fields are marked *


Follow Us

Shares