As you may know, Python is the third most used programming languages as of 2024. Developers all over the world are using it for back-end web development, data analysis, artificial intelligence, and scientific computing.
This useful language is easy to learn, and has a large community. Further, developers who have experience working with Python find better career opportunities than others.
Those advantages stated why developers everywhere should choose to learn Python.
This article by Designveloper will show you some of the best practices when using Python in your project. Enjoy!
Python’s Best Core Practices
To leverage the Python programming language effectively, you should understand and master the following best practices:
Code Readability
Code readability is essential for writing clean and maintainable Python code. It ensures that others, and even your future self, can easily understand and work with your code. Here are some key practices to enhance readability:
1. Use Clear and Descriptive Variable and Function Names
Choose names that clearly describe the purpose of the variable or function. Avoid abbreviations and single-letter names. For example, use calculate_total_price
instead of calc_total
and user_age
instead of age
. Descriptive names help anyone reading the code to quickly grasp its purpose.
2. Indent Consistently with Four Spaces
Consistent indentation is crucial in Python. It defines the structure and flow of the code. Use four spaces for each level of indentation. This makes the code easier to read and understand, as it visually separates different blocks and logic.
3. Break Down Long Lines of Code
Keep lines of code within a reasonable length, typically 79 characters. If a line becomes too long, break it into multiple lines. This can be done by splitting expressions or using parentheses to continue code on the next line. Breaking down long lines prevents horizontal scrolling and makes the code more readable.
4. Use Whitespace Effectively
Whitespace helps in organizing code and improving readability. Use blank lines to separate different sections of code and to group related lines. Add spaces around operators and after commas to make the code visually clear. However, avoid excessive whitespace that can clutter the code.
Coding Style
Coding style ensures that your Python code is consistent, clean, and easy to read. Complying with a style guide like PEP 8 helps maintain uniformity across projects. PEP 8 stands for Python Enhancement Proposal 8. Code that adheres to PEP 8 is easier to maintain and upgrade by yourself or other developers in the future. Further, PEP 8 rules help identify catch potential errors early and improve the overall quality of the code.
PEP 8 covers the following core practices of Python:
1. Indentation
Use four spaces for each level of indentation. Consistent indentation is essential for defining code blocks and ensuring proper execution. This practice helps maintain a clear structure and makes the code visually appealing.
2. Maximum Line Length
As we mentioned, you should limit all lines of code to a maximum of 79 characters. Keeping lines within this length prevents horizontal scrolling and makes your code more readable. If a line is too long, break it into multiple lines for better readability.
However, don’t stress if you occasionally go up to 80-100 characters. It’s generally acceptable as long as it doesn’t compromise readability.
For breaking long lines, use parentheses to continue the code on the next line:
wiki
=
(
"The Colt Python is a .357 Magnum caliber revolver formerly manufactured "
"by Colt's Manufacturing Company of Hartford, Connecticut. It is sometimes "
'referred to as a "Combat Magnum". It was first introduced in 1955, the '
"same year as Smith & Wesson's M29 .44 Magnum."
)
3. Blank Lines
Use blank lines to separate functions, classes, and different sections of code within functions. This improves readability and helps organize your code. Blank lines act as visual breaks, making it easier to navigate through your code.
4. Imports
Import entire modules instead of individual symbols within a module.
For example, for a top-level module canteen
that has a file canteen/sessions.py,
Yesimport canteen
import canteen.sessions
from canteen import sessions
Nofrom canteen import get_user # Symbol from canteen/__init__.py
from canteen.sessions import get_session # Symbol from canteen/sessions.py
Exception: For third-party code where documentation explicitly says to import individual symbols.
Further, place imports at the top of your file. Imports should be grouped in the following order:
- Standard library imports.
- Related third-party imports.
- Local application/library-specific imports.
You should put a blank line between each group of imports. This organization keeps your imports tidy and easy to manage.
5. Naming Conventions
There are a lot of different naming styles. It helps to be able to recognize what naming style is being used, independently from what they are used for.
For variable names, use lowercase letters with words separated by underscores (e.g., my_variable
). This makes variable names descriptive and easy to read. For class names, use CamelCase for class names (e.g., MyClass
). This distinguishes class names from other identifiers. For constants, use all uppercase letters with underscores separating words (e.g., MY_CONSTANT
). This highlights constants and makes them stand out.
Particularly:
Variables, functions, methods, packages, modules:Lower_case_with_underscores
Classes and Exceptions:CapWords
Protected methods and internal functions:_single_leading_underscore(self, ...)
Private methods:__double_leading_underscore(self, ...)
Constants:ALL_CAPS_WITH_UNDERSCORES
Further, you should consider some following guidelines for general naming:
Names to Avoid: Don’t use one-letter variables, especially the characters ‘l’ (lowercase letter el), ‘O’ (uppercase letter oh), or ‘I’ (uppercase letter eye).
Exception: In very short blocks, when the meaning is clearly visible from the immediate context.
Finefor e in elements:
e.mutate()
Avoid Redundant Labeling:
Yesimport audio
core = audio.Core()
controller = audio.Controller()
Noelements = ...
active_elements = ...
defunct_elements ...
Avoid Getter and Setter Methods:
Yesperson.age = 42
No
person.set_age(42)
6. Spaces Around Operators
Include spaces around operators and after commas to enhance readability. Do not place spaces directly inside brackets, braces, or parentheses. Proper spacing makes expressions easier to understand at a glance.
7. Comments
Write comments that are clear and concise. Use block comments to explain sections of code and inline comments for brief explanations of specific lines. Keep comments up to date and relevant to ensure they continue to provide useful information.
Use comments sparingly. It’s better to write code that is easy to understand on its own rather than relying heavily on comments. Often, well-named methods and variables can make code clearer than comments alone.
For example, instead of this:
# If the sign is a stop sign
if sign.color == 'red' and sign.sides == 8:
stop()
Use this:
def is_stop_sign(sign):
return sign.color == 'red' and sign.sides == 8
if is_stop_sign(sign):
stop()
When writing comments, remember to keep them brief and to the point, applying principles similar to those found in “Strunk and White.”
8. Docstrings
Use docstrings to describe the purpose of functions or classes. Place docstrings immediately after the definition of a function or class. Docstrings should explain what the function or class does, its parameters, and its return values, if applicable.
For functions with straightforward purposes, a one-line docstring is sufficient:
"""Return the pathname of ``foo``."""
For more complex functions or classes, use multiline docstrings. These should include:
- Summary Line: Briefly describe what the function or class does.
- Usage Example (if appropriate): Provide an example of how to use the function or class.
- Parameters: List and describe each parameter.
- Return Type and Semantics: Describe what the function returns, or state if it returns nothing.
Example:
"""Train a model to classify Foos and Bars.
Usage:
>>> import klassify
>>> data = [("green", "foo"), ("orange", "bar")]
>>> classifier = klassify.train(data)
:param train_data: A list of tuples of the form ``(color, label)``.
:rtype: A :class:`Classifier `
"""
Note:
- Use action words like “Return” rather than descriptive words like “Returns.”
- Document
__init__
methods in the class docstring to describe the class initialization:
class Person(object):
"""A simple representation of a human being.
:param name: A string, the person's name.
:param age: An int, the person's age.
""" def __init__(self, name, age):
self.name = name
self.age = age
Recommended reading: Best Javascript Tutorial for Beginners
Error Handling
Error handling is a crucial part of writing robust Python code. Here’s how to do it effectively:
1. Use Try-Except Blocks
Enclose code that might raise an exception in a try block. Follow this with an except block to catch and handle the exception. This approach lets you manage errors gracefully without stopping your program unexpectedly. For example:
try:
result = 10 / 0
except ZeroDivisionError:
print("You cannot divide by zero.")
In this example, the code inside the try block attempts to divide by zero. The except block catches this specific error and prints a user-friendly message instead of crashing the program.
2. Provide Informative Error Messages
When an error occurs, make sure your error messages are clear and helpful. They should explain what went wrong and, if possible, how to fix it. This helps users or developers quickly understand and resolve the issue. For instance:
try:
with open('file.txt', 'r') as file:
content = file.read()
except FileNotFoundError:
print("Error: The file 'file.txt' was not found.")
This message clearly tells the user that the file is missing, making it easier to diagnose the problem.
3. Use Custom Exceptions
For more specific error conditions, consider defining custom exceptions. This allows you to handle unique scenarios that standard exceptions might not cover. To create a custom exception, define a new class that inherits from the built-in Exception class:
class InvalidInputError(Exception):
"""Exception raised for errors in the input."""
def init(self, message):
self.message = message
super().init(self.message)
def process_input(value):
if not isinstance(value, int):
raise InvalidInputError("Input must be an integer.")
return value * 2
Here, InvalidInputError is a custom exception used to indicate when an invalid input is provided. This makes your error handling more precise and tailored to your application’s needs.
Efficiency
Efficiency in Python coding ensures your programs run smoothly and swiftly. Here’s how to keep your code efficient:
1. Optimize Code for Performance
Aim to write code that performs well, especially for tasks that are crucial or run frequently. Optimization might involve choosing faster algorithms or reducing the time complexity of operations. For example, using a list comprehension can be faster than using a loop for simple operations:
# Less efficient
result = []
for i in range(10):
result.append(i * 2)
# More efficient
result = [i * 2 for i in range(10)]
The list comprehension is not only more readable but also generally faster.
2. Use Appropriate Data Structures
Selecting the right data structure can significantly impact performance. For instance, use sets for membership tests because they are faster than lists:
# Inefficient for large data
items = [1, 2, 3, 4, 5]
if 3 in items:
print("Found")
# More efficient
items = {1, 2, 3, 4, 5}
if 3 in items:
print("Found")
Here, checking membership in a set is faster than in a list.
3. Profile Code to Identify Bottlenecks
Use profiling tools to find which parts of your code are slow. Python has built-in tools like cProfile
that can help:
import cProfile
def slow_function():
total = 0
for i in range(1000000):
total += i
return total
cProfile.run('slow_function()')
Profiling shows where the most time is spent, allowing you to focus your optimization efforts where they’ll have the most impact.
4. Avoid Unnecessary Computations
Minimize redundant calculations by storing results of expensive operations if they are needed multiple times. For instance:
# Less efficient
def compute():
return sum(i * i for i in range(1000))
result1 = compute()
result2 = compute()
# More efficient
def compute():
return sum(i * i for i in range(1000))
result = compute()
Here, computing result1
and result2
separately is redundant. Instead, compute once and reuse the result.
Testing
Strive for 100% code coverage, but don’t get obsessed over the coverage score.
1. General Testing Guidelines
- Use long, descriptive names. This often obviates the need for docstrings in test methods.
- Tests should be isolated. Don’t interact with a real database or network. Use a separate test database that gets torn down or uses mock objects.
- Prefer factories to fixtures.
- Never let incomplete tests pass, or else you run the risk of forgetting about them. Instead, add a placeholder like
assert False, "TODO: finish me"
2. Unit Tests
- Focus on one tiny bit of functionality.
- Should be fast, but a slow test is better than no test.
- It often makes sense to have one test case class for a single class or model.
import unittest
import factories
class PersonTest(unittest.TestCase):
def setUp(self):
self.person = factories.PersonFactory()
def test_has_age_in_dog_years(self):
self.assertEqual(self.person.dog_years, self.person.age / 7)
3. Functional Tests
Functional tests are higher-level tests that are closer to how an end user would interact with your application. They are typically used for web and GUI applications.
- Write tests as a scenario. Testcase and test method names should read like a scenario description.
- Use comments to write out stories, before writing the test code.
import unittest
class TestAUser(unittest.TestCase):
def test_can_write_a_blog_post(self):]
# Goes to the her dashboard
...
# Clicks "New Post"
...
# Fills out the post form
...
# Clicks "Submit"
...
# Can see the new post
...
Others Tips For Better Code
Like most computer programming languages, Python offers an extremely powerful development platform to create some of the most useful and robust applications imaginable. Here are our thoughts on Python's best practices to help you harness everything Python has to offer.
1. Follow Common Style Practices
Python has a system of community-generated proposals known as Python Enhancement Proposals (PEPs) which attempt to provide a basic set of guidelines and standards for a wide variety of topics when it comes to proper Python development.
While there are far too many specific styling guidelines to give examples here. Most Python developers make a concerted effort to follow the guidelines set forth in PEP8. So all code across the community has a similar look and feel.
To ensure compliance with PEP 8 coding style practices in a Python project, we at Designveloper often use automated tools and take the following measures:
Code Linting Tools: We use flake8 to check my code. Flake8 is a comprehensive tool that combines PyFlakes, pycodestyle, and Ned Batchelder's McCabe script. It helps ensure your code adheres to PEP 8 rules. You can configure flake8 in the .flake8
file to adjust the rules according to your project needs.
Editor/IDE Support: We use IDEs or editors that support PEP 8 checking, such as PyCharm or VSCode with integrated plugins. This helps detect and fix style issues as you write code.
CI/CD Pipeline: We set up PEP 8 checks in the CI/CD pipeline to ensure that all new code pushed to the repository is reviewed for compliance with style guidelines before being merged into the main branch.
2. Immediately Repair Your Broken Windows
This Python best practice is very crucial when creating a Python application. This is specifically more beneficial in the long-term to quickly acknowledge and repair broken windows immediately. Putting it off to finish a new component or module can and will often lead to further, more complex problems down the line.
While this theory, as it relates to crime prevention, is highly criticized and contested. It has some merit when it comes to the world of coding and application development.
It has even been stated that Microsoft, after a terrible production cycle with the original version of Microsoft Word, adopted a “zero defects methodology” to their great benefit, always focusing on fixing bugs and defects before new production code.
3. Get Acquainted With PyPI
Most projects will initially begin by utilizing existing projects on PyPI. And with nearly 100,000 at the time of writing to choose from. There’s almost certainly some code that fits your project’s needs. Once you’ve located a module you’re interested in using within your own project. The fun can begin.
While using proper syntax and documentation methods will always produce solid, clean code, perhaps one of the best tools to improve your use of Python is the epic module repository known as PyPI: The Python Package Index.
Conclusion
As a collective repository for thousands of Python projects. Including nearly every open or public Python project created. PyPI is an undeniably useful resource, no matter your Python experience level or project scope.
Source: The Best of the Best Practices (BOBP) Guide for Python via gist.github.com.
Notice how the test case and test method read together like "Test A User can write a blog post".
Hope that this blog post would help you with Python best practices in the future. Follow Designveloper’s Facebook, Twitter, and LinkedIn to update new articles every week.