Python Anti Design Patten
Anti-patterns work just opposite to predefined design pattern. We can assume its functioning by the name. In this approach, there are various techniques for the common problem, which can be formalized and can be a good development practice. Generally, anti-patterns are considered undesirable. Let’s understand some common anti-design patterns.
Important Features of the Anti-Pattern
This approach has some features which can be considerable during the programming. These features are given below.
Correctness
Anti-patterns break our code into the smaller chunks so that we can do the wrong things. Following is the simple example of accessing a private member outside of the class.
Example:
In the above code, we are trying to access the private class member directly. That will raise an error.
Maintainability
We can consider a program maintainable if it is easy to understand, easy to debug, and can make the changes when required. Anti-patterns make the program hard to maintain. Importing a module can be a suitable example of maintainability. A module consists of many useful predefined functions to perform a particular task. As we know, Python has many predefined modules and libraries, which make the program easy and maintainable. Let’s understand the following example.
Example –
Readability
Anti-patterns create complexity in the code so that code becomes hard to read and, understand. Programmers can make the common mistake that makes code less readable. These common mistakes include not using the zip() method to iterate over a pair of lists, asking for permission instead of forgiveness, not using the dict comprehension, using type() to compare types, etc. Let’s understand the following example.
Example –
In the above code, we have used the zip() method to compare the list pair. It is good practice. We used the for loop on the zip(nums, letters) function on the list pair. Python will automatically assign the first variable as the next value and the second variable as the second list’s next value.
Security
As we know that, Python is a high-level, dynamic-typed language, which means the user can change the behavior of his code and even can execute the code at runtime. Uses of exec can create the security issue in the code. Below is the example.
Example –
Good Practice
Performance
Performance is a big issue in any programming language. We can obtain the large performance using the appropriate functions and libraries. Performance can be affected if we do not use iteritems() to iterate over a large dictionary or use the key in the list to check if keys are contained in the list. Let’s understand the following example.
Example –
In the above code, we have changed the list into the set. It is much efficient behind the scene. In the list, Python will compare each number with the targeted number but using the set; it can directly access the targeted number.
Few Important Anti Pattern in Python
Below are the most common anti patterns in Python.
- Not Using with to open files
It is a bad practice not to using with statement while open the file. We need to remember closing the file via calling the close() function when processing it. If we close the file explicitly, there could be a chance of exceptions before the resource is closed. So we should open the file using the statement because it implements the context management protocol that releases the resource. We don’t need to close the resource explicitly. Let’s understand the following example.
Bad Practice
Good Practice
- Using Debugger in Production Code
It is the most common type of mistake that most of us have done at least once. When we debug the code and found the bug, we may leave the debugger in the production code. It can affect the behavior of the code. It is highly recommended to audit the code to eliminate invocation of debugger before checking it.
- Not using literal syntax to initialize empty list/dict/tuple
When we initialize the empty list by calling list() than using the empty literals, it make the program relatively slow. So it is recommended to use the empty literal to declare list, dictionary, and tuple. Let’s see the following example.
Bad Practice
Good Practice
- Avoid get() to return default values from a dictionary
Avoiding the get() method in the code affect the readability. We create a variable and assign the default value to it. When we check the dictionary for the specific key, if the key is available, then the key’s value is assigned to the value of the variable. We can easily do this using the get() method for the dictionary. Let’s understand the following example.
Bad Practice
Good Practice
- Inconsistent Return Type in function call
Returning more than one type of object can make the code confusing and complex to understand. It can also be a reason for bugs that will hard to resolve. A function can return the value rather than the given type (e.g., integer, constant, list, tuple); the caller check will check for the value being returned. It is recommended to return only one type of object of the function. Let’s see the following example.
Bad Practice
Good Practice
- Unnecessary use of list/dict/set Comprehension
Python provides the functions such as all, any, enumerate, iter, itertools.cycle, itertools.accumulate, which can directly work with the generator expression. We don’t need to use comprehension with these methods. The all() and any() function is also to provide the short-circuiting, but this behavior is lost if the comprehension is used. Let’s see the following example.
Bad practice:
Good Practice
- Unnecessary use of Python Generators
We don’t need to use the generator’s expression within a call to dict, list, or set because these three have the comprehension. So it is recommended to use comprehension instead of generators. Let’s understand the following example.
Bad Practice
Good Practice
- Avoid item() method to iterate over a dictionary
The item() method of the dictionary returns an iterable with the key-value tuples. The tuple can be unpacked using for loop. It is a simple, dynamic, and recommended approach. Let’s understand the following example.
Bad Practice:
Good Practice
- else clause on loop without a break statement
Python provides the facility to use the else statement with the loop. The else block is executed when the loop is empty and eventually loop becomes empty after its execution. This may seem the intended behavior, but this is not the intended behavior most of the time. So we should use the break statement in the loop if we are using the else with Python loop.
Let’s understand the below example.
Bad Practice
Example –
Output:
This list has the number This list does NOT has the number
The above code demonstrated, we haven’t used the break statement in for loop. Now try to understand the output; when we found the searched_number in the given list, we expect the loop to print only “This list has the number,” but it prints both results. This is because the list became empty; the else block is also executed.
Good Practice
Output:
This list has the number
- Indentation contains mixed space and tabs
This is the most common anti-patterns that programmers don’t care about while write the code, especially beginners only focuses on the indentation and they mix tabs and spaces. Let’s understand the following example.
Bad Practice
Output:
Hello, World! Goodbye, World!
Good Practice
Output:
Hello, World! Goodbye, World!
- Using Unpythonic loop
Generally, we prefer one obvious way to get the all elements of the list. We always do “Creating a loop that uses an incrementing index to access each element of the list within the loop”. This is not a good way to accessing each element in a list. We should use enumerate() function. Let’s understand the following example.
Bad Practice
Good Practice
- Assigning a lambda expression to a variable
The Python lambda function is also known as the anonymous function, and that is the biggest advantage over the def function. Being anonymous, the lambda method can be assigned to any larger expression. The assignment of the lambda method elements the benefit of the lambda function. If it requires assigning the lambda method to a variable, then create an equivalent method using the def statement. Let’s understand the following example.
Bad Practice
Good Practice
- Method could be a function
When a class method doesn’t contain any reference of the class (self) and is not preceded by the @staticmethod, it will raise “Method could be a function” error. This error is not so serious but we should check the code to determine the function really needs to be a class method. Let’s understand the following example.
Bad Practice
Good Practice
Or