Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
13 Bad Practices in Python Coding
BackEnd DevelopmentCoding Foundations

13 Bad Practices in Python Coding

Bad Practices

Anastasiia Tsurkan

by Anastasiia Tsurkan

Backend Developer

Sep, 2024
15 min read

facebooklinkedintwitter
copy
13 Bad Practices in Python Coding

In the ever-evolving landscape of Python programming, efficiency and clarity are paramount. This article delves into common bad coding practices in Python that developers, especially beginners, often fall into. We'll explore 13 widespread bad coding habits, offering insights on how to avoid these mistakes and improve the quality of your code.

Poor Code Organization and Structure

1. Lack of Modularization

Modularization refers to the practice of breaking down a program into smaller, manageable, and reusable parts such as functions and modules. This not only enhances readability but also improves maintainability.

Bad Practice Example:

# Non-modularized code
def main():
    num1 = 10
    num2 = 20
    sum = num1 + num2
    print(f"Sum: {sum}")

    multiplied = num1 * num2
    print(f"Product: {multiplied}")

# Rest of the code follows without any functional breakdown

main()

Issues:

  • All logic is inside a single function.
  • Difficult to maintain and extend.

Best Practice:

# Modularized code with functions

def calculate_sum(num1, num2):
    return num1 + num2

def calculate_product(num1, num2):
    return num1 * num2

def main():
    num1 = 10
    num2 = 20

    sum = calculate_sum(num1, num2)
    print(f"Sum: {sum}")

    product = calculate_product(num1, num2)
    print(f"Product: {product}")

main()

2. Improper Use of Global Variables

Global variables are accessible throughout the entire program, which can lead to unpredictable behavior and difficulty in tracking changes and debugging.

Bad Practice Example:

# Excessive use of global variables
counter = 0

def increment():
    global counter
    counter += 1

def decrement():
    global counter
    counter -= 1

increment()
print(f"Counter: {counter}")
decrement()
print(f"Counter: {counter}")

Issues:

  • counter is a global variable, which makes it susceptible to unintended modifications.
  • Hard to track its changes across different functions.

Best Practice:

# Using local variables and parameters

def increment(counter):
    return counter + 1

def decrement(counter):
    return counter - 1

counter = 0
counter = increment(counter)
print(f"Counter: {counter}")
counter = decrement(counter)
print(f"Counter: {counter}")

Python documentation on global and nonlocal statements.

Ignoring Pythonic Conventions

3. Not Following PEP 8 Guidelines

PEP 8 - Style Guide for Python Code. Adherence to these guidelines not only ensures code readability but also facilitates collaboration among Python developers. Let's look at some common violations of PEP 8 guidelines and their corrected forms.

Bad Practice Example:

# Non-compliant PEP 8 code
def calculateTax(price,tax_rate):
    return price + price*tax_rate

result=calculateTax(100,0.05)
print('Total cost: ',result)

Issues:

  • Function name should be in snake_case.
  • Lack of spaces after commas and around operators.
  • Variables should also be in snake_case.

Best practice:

# PEP 8 compliant code
def calculate_tax(price, tax_rate):
    return price + price * tax_rate

result = calculate_tax(100, 0.05)
print('Total cost: ', result)

4. Using Nested if Statements

Nested if statements can quickly become complicated and hard to read. Refactoring nested ifs can improve code readability and maintainability.

Bad Practice Example:

# Code with nested if statements
def user_access(user):
    if user.role == 'admin':
        if user.active:
            if user.has_permission('access_panel'):
                return True
    return False

Issues:

  • The nested structure makes it hard to follow the logic.
  • Difficult to modify and maintain.

Best practice:

Using logical operators.

# Refactored code with combined conditions
def user_access(user):
    return user.role == 'admin' and user.active and user.has_permission('access_panel')

5. Overlooking Pythonic Idioms

Pythonic idioms are ways of writing code that are not just syntactically correct but also embrace the philosophy (Zen of Python) of Python, focusing on readability and efficiency.

Bad Practice Example:

my_list = [1, 2, 3, 4, 5]
for i in range(len(my_list)):
    print(my_list[i])

Issues:

  • Using range(len(my_list)) is not Pythonic in this case to get the item from the list.
  • It's more complex and less readable.

Best Practice:

my_list = [1, 2, 3, 4, 5]
for item in my_list:
    print(item)

Run Code from Your Browser - No Installation Required

Run Code from Your Browser - No Installation Required

Error and Exception Handling Mistakes

6. Ignoring Exceptions

Exception handling in Python is crucial for managing unexpected errors in a program. Ignoring exceptions can lead to program crashes and unpredictable behavior.

Bad Practice Example:

# Ignoring exceptions
def divide_numbers(num1, num2):
    return num1 / num2

# This can cause a ZeroDivisionError if num2 is 0
result = divide_numbers(10, 0)
print(f"Result: {result}")

Issues:

  • No handling of potential ZeroDivisionError.
  • The program will crash if num2 is zero.

Best Practice:

# Properly handling exceptions
def divide_numbers(num1, num2):
    try:
        return num1 / num2
    except ZeroDivisionError:
        print("Error: Cannot divide by zero.")
        return None

result = divide_numbers(10, 0)
if result is not None:
    print(f"Result: {result}")
else:
    print("Division was unsuccessful.")

Python exception handling guide: Errors and Exceptions.

7. Overuse of Try-Except Blocks

While exception handling is important, overusing try-except blocks can hide errors that should be fixed or handled more specifically.

Bad Practice Example:

# Overuse of try-except blocks
def process_data(data):
    try:
        # Multiple operations that can fail
        print("Processing:", data)
        result = data[0] / data[1]
        print(f"Result: {result}")
    except:
        print("An error occurred.")

process_data([1, 0])

Issues:

  • Catches all exceptions, making it difficult to identify the real problem.
  • Can hide different types of errors (e.g., IndexError, ZeroDivisionError).

Best Practice:

# Specific and meaningful exception handling
def process_data(data):
    try:
        print("Processing:", data)
        result = data[0] / data[1]
        print(f"Result: {result}")
    except ZeroDivisionError:
        print("Error: Cannot divide by zero.")
    except IndexError:
        print("Error: Data index out of range.")
    except Exception as e:
        print(f"Unexpected error: {e}")

process_data([1, 0])

Inefficient Data Handling

8. Ineffective Use of Data Structures

The choice of data structures significantly impacts the performance and efficiency of a program. Using inappropriate data structures can lead to inefficient code.

Bad Practice Example:

# Inefficient use of list for frequent insertions and deletions
numbers = []
for i in range(10000):
    numbers.insert(0, i)  # Inserting at the beginning of the list

Issues:

  • Inserting at the beginning of a list is inefficient as it requires shifting all other elements.

Best Practice:

# Using deque from collections for efficient insertions and deletions
from collections import deque

numbers = deque()
for i in range(10000):
    numbers.appendleft(i)  # Efficient insertion at the beginning

9. Ignoring Generators and Iterators

Generators and iterators provide a way to handle large datasets efficiently by yielding items one at a time, rather than loading everything into memory.

Bad Practice Example:

# Inefficient way of handling large datasets
def get_large_dataset():
    return range(1000000)  # Returns a list of a million numbers

# Consumes significant memory
dataset = get_large_dataset()
for number in dataset:
    process(number)  # Some processing function

Issues:

  • The entire dataset is loaded into memory, which is inefficient for large datasets.

Best Practice:

# Efficient handling with a generator
def get_large_dataset():
    for i in range(1000000):
        yield i  # Yields numbers one at a time

# Memory-efficient
for number in get_large_dataset():
    process(number)

Performance Issues

10. Not Utilizing List Comprehensions and Map/Filter Functions

Python offers powerful constructs like list comprehensions, map, and filter functions, which can lead to more efficient and readable code compared to traditional loops.

Bad Practice Example:

# Using loops instead of list comprehensions or map/filter
squared_numbers = []
for num in range(10):
    squared_numbers.append(num * num)

Issues:

  • More verbose and potentially slower than list comprehensions.
  • Less Pythonic.

Best Practice:

# Using list comprehension
squared_numbers = [num * num for num in range(10)]

The official guide on list comprehensions.

Code Readability and Maintainability

11. Writing Non-Self-Explanatory Code

Readable code is not just about following syntax; it's about making your code understandable to others (and your future self). Self-explanatory code often requires fewer comments and is easier to maintain.

Bad Practice Example:

# Non-self-explanatory code
def proc_data(d):
    r = [i for i in d if i%2 == 0]
    return sum(r)

data = [1, 2, 3, 4, 5, 6]
print(proc_data(data))

Issues:

  • Function and variable names (proc_data, d, r) are not descriptive.
  • Lack of clarity on what the function does.

Best Practices:

# Self-explanatory code
def sum_of_even_numbers(numbers):
    even_numbers = [num for num in numbers if num % 2 == 0]
    return sum(even_numbers)

data = [1, 2, 3, 4, 5, 6]
print(sum_of_even_numbers(data))

12. Not Using Docstrings and Comments Appropriately

Docstrings and comments are essential for explaining the purpose, usage, and intricacies of the code, which is crucial for long-term maintenance.

Bad Practice Example:

# Code without docstrings and comments
def calculate_area(l, w):
    return l * w

Issues:

  • No explanation of what the function does or what parameters l and w represent.

Best Practice:

# Code with appropriate docstrings and comments
def calculate_area(length, width):
    """
    Calculate the area of a rectangle.

    Args:
    length (float): The length of the rectangle.
    width (float): The width of the rectangle.

    Returns:
    float: The area of the rectangle.
    """
    # Multiplying length and width to get the area
    return length * width

Python docstring guide: PEP 257 - Docstring Conventions.

Start Learning Coding today and boost your Career Potential

Start Learning Coding today and boost your Career Potential

Dependency and Environment Management

13. Ignoring Virtual Environments

Virtual environments in Python are a crucial tool for managing dependencies and Python versions for different projects. They prevent conflicts between project requirements and allow for a clean, isolated workspace for each project.

Without Virtual Environments:

Consider a scenario where you're working on two projects, ProjectA and ProjectB. ProjectA requires Django 2.2, while ProjectB needs Django 3.1.

Global Python Environment:
- Django 2.2
  • You install Django 2.2 globally for ProjectA.
  • When you switch to ProjectB and upgrade to Django 3.1, it breaks ProjectA.

With Virtual Environments:

Using virtual environments, you can maintain separate dependencies for each project.

# For ProjectA
$ python -m venv projectA_env
$ source projectA_env/bin/activate
(projectA_env) $ pip install Django==2.2

# For ProjectB
$ python -m venv projectB_env
$ source projectB_env/bin/activate
(projectB_env) $ pip install Django==3.1
  • ProjectA and ProjectB have their own isolated environments with specific Django versions.
  • There is no interference between projects.

Conclusion

As we've explored, avoiding these 13 bad coding practices is essential for writing Python code that is clean, maintainable, and efficient. Eliminating bad coding habits, such as neglecting exception handling, overusing global variables, or hardcoding values, will significantly enhance your programming skills. By following best practices like those outlined in PEP 8, using Pythonic idioms, and utilizing built-in tools, you can write code that not only works but is also scalable and easy to read. Remember, becoming a proficient Python developer is an ongoing journey—avoid these pitfalls, and you'll be well on your way to mastering Python!

Ця стаття була корисною?

Поділитися:

facebooklinkedintwitter
copy

Ця стаття була корисною?

Поділитися:

facebooklinkedintwitter
copy

Зміст

Ми дуже хвилюємося, що щось пішло не так. Що трапилося?
some-alt