# -*- coding: utf-8 -*-
"""Clean Coding Principles in Python.ipynb
Automatically generated by Colab.
Original file is located at
https://colab.research.google.com/drive/1IsKwWLs2_X_WnqGwG5XFhri5XCnwQKnV
# What is Clean Code?
**Clean code is a set of rules and principles that help to keep our code readable,
maintainable, and extendable.**

*image source: stephanosterburg*
Writing code is easy, but writing good, clean code is hard.
# Clean coding principles in Python:
1. **DRY (Don't Repeat Yourself)** ⏰
- Avoid code duplication by abstracting repeated code into functions or classes.
- This makes the code easier to maintain and reduces the risk of
inconsistencies.
2. **KISS (Keep It Simple, Stupid)** ⭐
- Keep your code as simple as possible.
- Avoid unnecessary complexity and over-engineering.
- Simple code is easier to read, understand, and maintain.
3. **Single Responsibility Principle (SRP)** ✈
- Each class or function should have only one responsibility.
- This makes the code more modular and easier to test and maintain.
4. **Meaningful Names** ✌
- Use descriptive and meaningful names for variables, functions, and classes.
- This improves code readability and helps others understand the purpose of each
component.
5. **Comments and Documentation** ✨
- Write comments to explain why certain decisions were made, not what the code
is doing.
- Use docstrings to document modules, classes, and functions.
- Keep comments and documentation up-to-date with code changes.
These principles help ensure your code is clean, readable, and maintainable.
# Interactive Example 1: Refactoring Duplicate Code
* Identify duplicate code blocks.
* Refactor them into reusable functions or methods.
"""
# Unclean Code:
def print_user_details(name, age):
print(f"Name: {name}")
print(f"Age: {age}")
def print_employee_details(name, age, employee_id):
print(f"Name: {name}")
print(f"Age: {age}")
print(f"Employee ID: {employee_id}")
print_user_details("Alice", 30)
print_employee_details("Bob", 25, "E123")
# Bad Code Explanation:
# - The functions print_user_details and print_employee_details have duplicated
code.
# - This makes the code harder to maintain and increases the risk of
inconsistencies.
def print_details(name, age, employee_id=None):
print(f"Name: {name}")
print(f"Age: {age}")
if employee_id:
print(f"Employee ID: {employee_id}")
print_details("Alice", 30)
print_details("Bob", 25, "E123")
# Clean Code Explanation:
# - Refactored the functions into a single function with an optional parameter.
# - This reduces code duplication and makes the code easier to maintain.
"""# Interactive Example 2: The DRY Principle in Python
- DRY stands for "Don't Repeat Yourself".
- It emphasizes reducing code duplication.
- Helps in maintaining and updating code efficiently.
"""
# Unclean Code:
def calculate_area(length, width):
return length * width
def calculate_perimeter(length, width):
return 2 * (length + width)
length = 5
width = 3
area = calculate_area(length, width)
perimeter = calculate_perimeter(length, width)
print(f"Area: {area}, Perimeter: {perimeter}")
# Bad Code Explanation:
# - The functions calculate_area and calculate_perimeter have similar parameters
and logic.
# - This leads to code duplication, making it harder to maintain and update.
#Clean Code
def calculate_area_and_perimeter(length, width):
area = length * width
perimeter = 2 * (length + width)
return area, perimeter
length = 5
width = 3
area, perimeter = calculate_area_and_perimeter(length, width)
print(f"Area: {area}, Perimeter: {perimeter}")
"""# The KISS Principle in Python
Simple code is easier to read, understand, and maintain.
* KISS stands for “Keep It Simple, Stupid”.
* Encourages simplicity and avoiding unnecessary complexity.
* Simple code is easier to read, understand, and maintain.
"""
# Unclean Code:
def is_even(number):
if number % 2 == 0:
return True
else:
return False
# Bad Code Explanation:
# - The if-else statement is unnecessary and adds complexity.
# - The same result can be achieved with a simpler expression.
# Clean Code:
def is_even(number):
return number % 2 == 0
"""
* Simplify complex logic.
* Use built-in functions and libraries.
"""
# Unclean Code
def get_even_numbers(numbers):
even_numbers = []
for number in numbers:
if number % 2 == 0:
even_numbers.append(number)
return even_numbers
# Bad Code Explanation:
# - The for loop and if statement add unnecessary complexity.
# - The same result can be achieved with a list comprehension.
#Clean Code:
def get_even_numbers(numbers):
return [number for number in numbers if number % 2 == 0]
"""**SOLID Principles in Python**
SOLID is a set of five object-oriented design principles that can help you write
more maintainable, flexible, and scalable code based on well-designed, cleanly
structured classes.
* Single-responsibility principle (SRP)
* Open–closed principle (OCP)
* Liskov substitution principle (LSP)
* Interface segregation principle (ISP)
* Dependency inversion principle (DIP)
**Single Responsibility Principle (SRP)**
* A class should have only one reason to change.
* Each class should have a single responsibility.
"""
# Unclean Code:
class User:
def __init__(self, name, email):
self.name = name
self.email = email
def send_email(self, message):
# Code to send email
pass
# Bad Code Explanation:
# - The User class has multiple responsibilities (user data and email sending).
# - This violates the Single Responsibility Principle.
# Clean Code:
class User:
def __init__(self, name, email):
self.name = name
self.email = email
class EmailService:
def send_email(self, user, message):
# Code to send email
pass
"""**Open/Closed Principle (OCP)**
* Software entities should be open for extension but closed for modification.
"""
# Unclean code
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius * self.radius
# This code violates OCP because adding a new shape requires modifying existing
classes.
# Clean code:
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius * self.radius
# New shapes can be added by extending the Shape class without modifying existing
code.
"""**Liskov Substitution Principle (LSP)**
* Subtypes must be substitutable for their base types.
"""
class Bird:
def fly(self):
pass
class Ostrich(Bird):
def fly(self):
# This violates LSP because Ostrich cannot fly, which breaks the expected
behavior of Bird.
raise Exception("Ostriches can't fly")
class Bird:
def move(self):
pass
class FlyingBird(Bird):
def move(self):
print("Flying")
class Ostrich(Bird):
def move(self):
print("Running")
# The move method is used instead of fly, allowing Ostrich to have a different
behavior without violating LSP.
"""**Interface Segregation Principle (ISP)**
* Clients should not be forced to depend on interfaces they do not use.
"""
# Unclean Code:
class Worker:
def work(self):
pass
def eat(self):
# This violates ISP because not all workers may need to implement the eat
method.
pass
# Clean Code
class Workable:
def work(self):
pass
class Eatable:
def eat(self):
pass
class Worker(Workable, Eatable):
def work(self):
pass
def eat(self):
pass
# Separate interfaces for work and eat ensure that classes only implement what they
need.
"""**Dependency Inversion Principle (DIP)**
* High-level modules should not depend on low-level modules. Both should depend
on abstractions.
"""
# Unclean Code:
class BackendDeveloper:
def develop(self):
return "Writing Python code"
class FrontendDeveloper:
def develop(self):
return "Writing JavaScript code"
class Project:
def __init__(self):
self.backend = BackendDeveloper()
self.frontend = FrontendDeveloper()
def develop(self):
# This violates DIP because Project depends directly on BackendDeveloper
and FrontendDeveloper.
return f"{self.backend.develop()} and {self.frontend.develop()}"
# Clean Code:
class Developer:
def develop(self):
pass
class BackendDeveloper(Developer):
def develop(self):
return "Writing Python code"
class FrontendDeveloper(Developer):
def develop(self):
return "Writing JavaScript code"
class Project:
def __init__(self, developers):
self.developers = developers
def develop(self):
# Project depends on the abstract Developer class, not specific
implementations.
return " and ".join([developer.develop() for developer in self.developers])
developers = [BackendDeveloper(), FrontendDeveloper()]
project = Project(developers)
print(project.develop())
"""# Code Organization and Naming Conventions
* Organize code into modules and packages.
* Use meaningful and descriptive names.
* Follow naming conventions (e.g., snake_case for variables and functions)..
"""
# Unclean Code:
def calc(x, y):
return x + y
a = 5
b = 3
result = calc(a, b)
print(result)
# Bad Code Explanation:
# - The function and variable names are not descriptive.
# - This makes the code harder to understand.
# Clean Code:
def calculate_sum(first_number, second_number):
return first_number + second_number
first_number = 5
second_number = 3
result = calculate_sum(first_number, second_number)
print(result)
#Use pronounceable names
from datetime import datetime
# This is bad
genyyyymmddhhmmss = datetime.strptime('04/27/95 07:14:22', '%m/%d/%y %H:%M:%S')
# This is good
generation_datetime = datetime.strptime('04/27/95 07:14:22', '%m/%d/%y %H:%M:%S')
# Avoid using ambiguous abbreviations
# This is bad
fna = 'Bob'
cre_tmstp = 1621535852
# This is good
first_name = 'Bob'
creation_timestamp = 1621535852
# Always use the same vocabulary
# This is bad
client_first_name = 'Bob'
customer_last_name = 'Smith'
# This is good
client_first_name = 'Bob'
client_last_name = 'Smith'
#Don't add redundant context
# This is bad
class Person:
def __init__(self, person_first_name, person_last_name, person_age):
self.person_first_name = person_first_name
self.person_last_name = person_last_name
self.person_age = person_age
# This is good
class Person:
def __init__(self, first_name, last_name, age):
self.first_name = first_name
self.last_name = last_name
self.age = age
"""# Comments and Documentation
* Use comments to explain why, not what.
* Write docstrings for modules, classes, and functions.
* Keep comments up-to-date with code changes.
"""
# Unclean Code:
def add(a, b):
# This function adds two numbers
return a + b
# Bad Code Explanation:
# - The comment explains what the code does, which is redundant.
# - It does not provide any additional context or explanation.
def add(a, b):
"""
Add two numbers.
Parameters:
a (int or float): The first number.
b (int or float): The second number.
Returns:
int or float: The sum of the two numbers.
"""
return a + b
"""# PEP 8 (Python Enhancement Proposal)
PEP 8 is a style guide that describes the coding standards for Python. It's the
most popular guide within the Python community. The most important rules state the
following:
**PEP 8 naming conventions:**
* class names should be CamelCase (MyClass)
* variable names should be snake_case and all lowercase (first_name)
* function names should be snake_case and all lowercase (quick_sort())
* constants should be snake_case and all uppercase (PI = 3.14159)
* modules should have short, snake_case names and all lowercase (numpy)
* single quotes and double quotes are treated the same (just pick one and be
consistent)
**PEP 8 line formatting:**
indent using 4 spaces (spaces are preferred over tabs)
* lines should not be longer than 79 characters
* top-level function and class definitions are surrounded with two blank lines
* method definitions inside a class are surrounded by a single blank line
* imports should be on separate lines
**PEP 8 whitespace: **
* avoid extra spaces within brackets or braces
* avoid trailing whitespace anywhere
* always surround binary operators with a single space on either side
* if operators with different priorities are used, consider adding whitespace
* around the operators with the lowest priority
* don't use spaces around the = sign when used to indicate a keyword argument
* don't use spaces around the = sign when used to indicate a keyword argument
**PEP 8 comments:**
* comments should not contradict the code
* comments should be complete sentences
* comments should have a space after the # sign with the first word capitalized
* multi-line comments used in functions (docstrings) should have a short single-
line description followed by more text
multi-line comments used in functions (docstrings) should have a short
"""
# Bad Code
def example():
a = 1
b = 2
print(a + b)
# Good Code
def example():
a = 1
b = 2
print(a + b)
# Bad Code
def example():
print("This is a very long line that exceeds the recommended line length of 79
characters.")
# Good Code
def example():
print("This is a line that adheres to the recommended line length.")
# Bad Code
import os, sys
import numpy as np
# Good Code
import os
import sys
import numpy as np
# Bad Code
def myFunction():
myVariable = 10
return myVariable
# Good Code
def my_function():
my_variable = 10
return my_variable