Improve Your Python Code Readability and Maintenance by Avoiding These 3 Mistakes

Improve Your Python Code Readability and Maintenance by Avoiding These 3 Mistakes

Writing Python code is easy, but writing good, maintainable, readable Python code is not as such.

TLDR; Avoid these 3 mistakes for clearer Python code: overusing dictionaries, using strings for variations, and not using type hinting. Consider data classes and enums for structured data and variations, and use type hinting for readability.

When you are trying to prototype an idea or start a new project in Python, it is generally a quicker process than using other languages in most cases. The simplicity of Python's syntax side by side with its dynamic nature is extremely attractive to anyone starting, but this can also be detrimental in the long run. As you advance in your career, you begin to see how shipping new software is just part of the big picture, and there is a larger aspect called maintaining old software, or as we call it, legacy code.

with that said, here are some mistakes to avoid if you want to make it easier for people and your future self to maintain your code.

Mistake #1 Using dictionaries for everything

Dictionaries are a fantastic data structure and incredibly powerful in Python, but overusing them can make your code difficult to trace.

The primary issue with dictionaries is their lack of a defined structure. Without a clear structure, it's challenging to know what to expect from a dictionary at a specific point in your software. What keys are present, and what types of data are held within? It will require extra effort from you to ensure the structure and the existence of certain keys/values. To avoid this, you can use Data classes.

The main advantage of Data classes is the presence of a defined structure, which can be extremely helpful if your data has a consistent structure that will always be satisfied, for example.

from dataclasses import dataclass

@dataclass
class User:
    name: str
    url: str
    age: int
    address: str
new_user = User(name="Mo", url="www.m-ashour.space", age=28, address="Earth")
#Using dataclass, you can access the data inside directly like this
>> new_user.name
>> new_user.age

#compare using dataclasses here with using dict
new_user_dict = {"name":"Mo", "url" : "www.m-ashour.space", "age":28, "address":"Earth"}
#here, you don't have an enforced defined structure and you are vurnable to more mistakes

>> new_user_dict["name"]
>> new_user_dict["age"]

As you can see, the advantage of a defined structure is quite obvious even in a very simple example. imagine yourself reading this code in 3 years, which one would be easier to maintain and read?

Of course, it's not always the right choice!

Data classes are easier to write and maintain, but they are not the most lightweight, if performance is an issue, you might look at other solutions which we can discuss in another article.

Mistake #2 Using Strings to distinguish variations

Strings are powerful and incredibly useful, but misusing them can lead to numerous problems and potential issues.

To represent variations, you need a well-defined and structured method to explicitly implement them and limit the options to only the supported variations. This way, you can prevent any potential issues arising from referring to or passing a non-supported, non-implemented variation. In this case, using strings will not fulfill these requirements, but using Enums will. Allow me to use the same example.

Don't

from dataclasses import dataclass

@dataclass
class User:
    name: str
    url: str
    age: int
    address: str
    #let's add a user type
    user_type: str
#here, using user_type as string, will not give any indication on what user types we have

Please Do

from dataclasses import dataclass
from enum import Enum

class UserType(Enum):
    STANDARD = "STANDARD"
    PRO = "PRO"
    BUSINESS = "BUSINESS"

@dataclass
class User:
    name: str
    url: str
    age: int
    address: str
    user_type: UserType
#here you can clearly understand the types of users that the code supports

As you can see, Enums can provide an incredible boost in understanding the code and can provide help in how to use it. it's a timeless documentation on its own, even on the basic level. There is more to Enums, but that's a separate topic for a separate post.

Mistake #3 Not using type hinting

Even though type hinting in Python doesn't enforce anything or check the types during runtime (since we don't have compile time), it still provides readability on various levels.

Type hinting wasn't introduced in Python until version 3.5. While it's not native to the language or fully matured, it still offers readability and productivity enhancements when maintaining existing code or writing new code. Current Code editors and IDEs now have good integration with it, and depending on the types you hint your variables with, they can suggest appropriate methods. Additionally, it serves as basic documentation for your functions.

For example,

from typing import List, Tuple
def draw_line(x,y):
    .....

#using type hinting
def draw_line(x:List[float], y:List[float]) -> List[Tuple[float,float]]:
    .....

Can you see the difference in readability? this is a big difference for anyone reading your code (including you).

Conclusion

In this Article, I walked you through 3 main mistakes that can make your code more trouble to maintain and read. So to sum it up

  • Data classes are a better option than Dicts for structured well-defined data bundles

  • Enums speak louder and clearer than Strings when it comes to domain-defined variations

  • Type Hinting is a great advisor and a future guide for your colleagues and your future-self

These are not the only mistakes, there are more that we can learn from. Let me know in the comments about some of them!

See you in the next one!

Did you find this article valuable?

Support Mohamed Ashour by becoming a sponsor. Any amount is appreciated!