There are many reasons to program using Python, chief among them being that the language is incredibly flexible. Few languages have Python’s ability to morph to your particular coding style, rather than forcing you to code in a certain way. While Python does require you to adhere to certain conventions such as adding white space (see the Pep-8 style guide) in order to make the language easy to read and understand, it still has the flexibility to let developers code in a way that feels natural to them, improving developer efficiency and reducing the potential for errors.
In addition, this flexibility has another key benefit: It lets a more advanced developer use the style best suited to solve a particular problem. Rather than force the coding solution to match the environment, Python makes it possible for the coding solution to reflect the needs of the application task.
There are four main Python coding styles: imperative, functional, object-oriented, and procedural. (Some people combine imperative and functional coding styles. I choose not to combine them here because I view them as completely separate styles.) You may or may not agree that all four forms are valid or even useful—but nevertheless Python makes them all available. Let’s take a look at the pros and cons of each approach as well as some examples of usage.
Comparing the four Python coding styles
- Functional: Every statement is treated as a mathematical equation and any form of state or mutable data are avoided. The main advantage of this approach is that there aren’t any side effects to consider. In addition, this coding style lends itself well to parallel processing because there is no state to consider. Many developers prefer this coding style for recursion and for lambda calculus.
- Imperative: Computation is performed as a direct change to program state. This style is especially useful when manipulating data structures and produces elegant, but simple, code.
- Object-oriented: Relies on data fields that are treated as objects and manipulated only through prescribed methods. Python doesn’t fully support this coding form because it can’t implement features such as data hiding. However, this remains a useful coding style for complex applications because it supports encapsulation and polymorphism. This coding style also favors code reuse.
- Procedural: Tasks are treated as step-by-step iterations where common tasks are placed in functions that are called as needed. This coding style favors iteration, sequencing, selection, and modularization.
The examples used here all answer a common question so that you can more easily compare the coding styles. Normally, you’d use a particular coding style to meet a specific need, but showing four different examples wouldn’t be as helpful because you really need to see the same example presented four different ways to form an opinion on each style. So all these examples answer the same need, computing the sum of the following list:
MyList = [1, 2, 3, 4, 5]
1. Using the functional coding style
The functional coding style treats everything like a math equation. There are a number of ways to compute the sum of
MyList using a functional style. However, the two most common would be to use a local function or a lambda expression—note that they don’t necessarily have to conform to Pep-8 in order to work. Here is the local function approach in Python 3.4:
import functools MyList = [1, 2, 3, 4, 5] def AddIt(X, Y): return (X + Y) Sum = functools.reduce(AddIt, MyList) print(Sum)
The lambda expression approach is simpler (or, at least, shorter):
import functools MyList = [1, 2, 3, 4, 5] Sum = functools.reduce(lambda x, y: x + y, MyList) print(Sum)
2. Using the imperative coding style
The focus of imperative programming is on how a program operates. It changes state information as needed in order to achieve a goal. Here is an example of how the imperative coding style might look for adding the elements of
MyList = [1, 2, 3, 4, 5] Sum = 0 for X in MyList: Sum += X print(Sum)
Notice how this sample differs from the previous samples. The value of
Sum changes with each iteration of the loop. As a result,
Sum has state.
3. Using the object-oriented coding style
The object-oriented coding style is all about increasing the ability of applications to reuse code and making code easier to understand. The encapsulation that object-orientation provides allows developers to treat code as a black box. Using object-orientation features like inheritance makes it easier to expand the functionality of existing code. Here is the
MyList example in object-oriented form:
class ChangeList: def __init__(self, MyList): if type(MyList) is list: self.MyList = MyList else: self.MyList = def DoAdd(self): self.Sum = sum(self.MyList) CreateSum = ChangeList([1, 2, 3, 4, 5]) CreateSum.DoAdd() print(CreateSum.Sum)
In this case,
CreateSum is an instance of
ChangeList. The inner workings of
ChangeList don’t matter to the person using it. All that really matters is that you can create an instance using a list and then call the
DoAdd() method to output the sum of the list elements. Because the inner workings are hidden, the overall application can be easier to understand.
4. Using the procedural coding style
The procedural style relies on procedure calls to create modularized code. It seeks to simplify the application code by creating small pieces that a developer can view easily. Even though the procedural coding style is an older form of application development, it’s still a viable approach when a task lends itself to step-by-step execution. Here’s an example of the procedural coding style:
def DoAdd(MyList): Sum = 0 if type(MyList) is list: for X in MyList: Sum += X return Sum MyList = [1, 2, 3, 4, 5] print(DoAdd(MyList))
Notice how the use of a function,
DoAdd(), simplifies the overall code in this case. The execution is still systematic, but the code is easier to understand because it’s broken into chunks.
Selecting a coding style
I’ve listed the four coding styles in order of preference. In other words, if you can use the functional coding style, you should do so, but not at the expense of developer efficiency or of producing a straightforward solution to a particular coding problem. (Some developers may not even agree that functional is the preferred coding style—everyone has an opinion on which style is best.)
If you don’t know which coding style will work best for a given task, try several of the styles to determine which one helps you solve the problem fastest and with the least amount of convoluted code. In fact, you may find that a single style doesn’t truly solve the problem. There aren’t any rules that say you can’t combine styles as needed. Python doesn’t stop in the middle of interpreting your application and display a style error when you mix styles. In fact, this is another good example of Python’s flexibility—the ability to mix and match coding styles as needed.
Finally, when you find an efficient solution to a problem, it’s important to clearly document it so that you—or another programmer—can come back six months later and not have to reinvent the wheel. That’s especially important when mixing programming, because flexibility can comes with a price in clarity.
Done right, today’s problem solved can become tomorrow’s time-saving template in terms of choosing the right Python programming style.