prscrew.com

Essential Python Practices for Daily Production Projects

Written on

Chapter 1: Introduction to Python in Production

In this section, we’ll delve into practical aspects of managing Python projects. My aim is to share insights that can significantly enhance your programming journey. Today, I’ll outline my approach to structuring, coding, testing, and deploying a Python project in real-world scenarios.

What do I do?

To provide some background, I work as a Solutions Engineer at a company in Spain. My responsibilities range from developing customized systems to facilitating seamless API integration for new clients. My team utilizes FastAPI for our APIs and Streamlit for a straightforward User Interface (UI).

In this article, I’ll cover:

  • My project structuring methods
  • Key Python features that can assist you

Let’s jump right in!

How I Structure Python Projects

Creating a new project structure can be daunting. You may find yourself pondering about the initial file to create, the necessary folders, and more. Over time, every programmer develops a unique structuring style that simplifies their workflow. Here’s a list of guidelines I follow:

  • Modules and Packages Should Be Intuitive

Each module should have a name that clearly indicates its purpose. A poorly named module can lead to confusion. For example, consider a module named connection.py. What does it connect to? A database? An SSH server? By organizing it into a package labeled db, it’s clear that it pertains to database connections.

my_app

├── __init__.py

└── db

├── __init__.py

└── connection.py

  • Maintain Order

I prioritize organization within my code. I always consider how other developers might interpret my work, especially if they need to continue the project in my absence. I want to avoid scenarios where someone might exclaim, "What is this mess?"

As part of my role, I develop APIs that consist of various endpoints. Each endpoint corresponds to a specific action, such as managing Orders or Products.

# main.py

from fastapi import FastAPI # Ensure FastAPI is installed

app = FastAPI()

@app.post('/order')

async def create_order(payload):

# Function to create a new order

pass

@app.patch('/order/{id}')

async def update_order(payload, id):

# Function to update an order

pass

@app.get('/order/{id}')

async def get_order(id):

# Function to retrieve an order by ID

pass

@app.get('/orders')

async def all_orders():

# Function to return all orders

pass

@app.delete('/order/{id}')

async def delete_order(id):

# Function to delete an order by ID

pass

As demonstrated, the list of endpoints can quickly expand if all necessary functions are crammed into a single file. A better approach is to categorize them. I create a routes package to organize endpoints logically.

my_app

├── __init__.py

├── main.py

└── routes

├── __init__.py

└── order.py

└── product.py

For example, all order-related endpoints can reside within order.py:

# routes/order.py

from fastapi import APIRouter

router = APIRouter()

@router.post('/order')

async def create_order(payload):

# Function to create a new order

pass

Now, I can seamlessly integrate this route into my main application:

from fastapi import FastAPI

from routes import order

app = FastAPI()

# Integrate the order routes

app.include_router(order.router)

  • Adopt the DRY Principle

Repetitive code can be counterproductive. Striving to eliminate redundancy requires careful planning. The DRY principle emphasizes that every piece of information should have a single, clear representation.

In my project structure, I include a commons package to house shared elements across modules:

my_app

├── __init__.py

├── main.py

└── commons

├── __init__.py

└── base_response.py

Consider a scenario where your project needs to return a standardized response object. Instead of duplicating this structure across different modules, I create a base response object that subsequent classes can inherit.

# commons/base_response.py

class BaseResponse:

def __init__(self):

pass

def status(self, code):

return 200 < code <= 299
  • Controllers, Models, and Schemas

You might wonder where the logic for creating products or placing orders resides. Previously, I adhered to the MVC pattern, but I prefer to maintain a more streamlined structure. Each functional area, such as orders, has its dedicated package that includes all relevant models and logic.

my_app

├── order

│ ├── __init__.py

│ └── schemas.py

│ └── response.py # Inherits from base_response.py

  • Testing

As expected, I have a tests folder at the root level of the project. I favor using pytest, and each tests folder includes a conftest.py module for shared fixtures.

my_app

├── tests

│ ├── __init__.py

│ └── conftest.py

For more details on testing, stay tuned.

  • Managing Project Dependencies

Every project requires specific dependencies to function correctly. These can include:

  • A requirements.txt file that lists all Python dependencies
  • A settings.py file for project configurations
  • A Dockerfile for containerization
  • A Makefile for commands and configurations

my_app

├── settings.py

├── Dockerfile

├── Makefile

├── README.md

├── requirements.txt

Chapter 2: Key Python Features for Enhanced Programming

Now, let’s explore some Python features that can enhance your programming experience.

  • Utilizing Match/Case

Introduced in Python 3.10, the match statement offers a cleaner alternative to complex conditional structures. It can streamline your code, particularly when faced with multiple if-elif statements.

match expression:

case a:

# Handle case a

case b:

# Handle case b

case _:

# Default case
  • Generic Types with Typing

Generic types in Python allow for more flexible and reusable code. They can be particularly useful when you are unsure of the data type in advance.

# base_response.py

class BaseResponse:

def another_method(self) -> T:

# Return a generic type

pass

  • @override Decorator

In my examples, I demonstrated a base response class that can be extended. To clarify when methods are being overridden, I utilize the @override decorator from PEP 698.

from typing import override

from commons.base_response import BaseResponse

class Response(BaseResponse):

@override

def another_method(self):

# Custom implementation

pass

Final Thoughts

Every project is an opportunity to learn and apply new skills. While starting a new project can be intimidating, that feeling dissipates as I dive into organizing my work.

Structuring your projects is akin to tidying up your living space. Everyone has their methods, but the goal remains the same: to create an organized and clean environment so that you or anyone else can easily navigate through it.

Thank you for taking the time to read my article! If you found this helpful and would like to receive similar content, consider subscribing to the community.

This video showcases five quick Python projects suitable for beginners, all of which can be completed in a single day.

This video provides insights into program structure as part of the Python For Production series, offering free lessons from a professional developer.

Share the page:

Twitter Facebook Reddit LinkIn

-----------------------

Recent Post:

Finding Happiness in the Small Things: Love or Hate

Discover how contentment and self-acceptance can lead to true happiness, while ambition and guilt can hold you back.

A Family's Life Transformed: Discoveries in An Enemy of the People

Explore the pivotal moments in a family's life as they navigate discoveries in An Enemy of the People, highlighting societal and scientific themes.

Exploring Love and Aliens: Are Extraterrestrials Beneficial or Harmful?

A deep dive into the complexities of love, fear, and the implications of extraterrestrial existence.

Embrace the Fear: Why Your First Chapter Isn't as Crucial as You Think

Discover why the first chapter of your novel isn't as critical as you believe and learn how to overcome the fear of the blank page.

Here’s How Mindfulness Meditation Transforms the Brain

Discover how mindfulness meditation can reshape brain structures and improve mental health based on scientific evidence.

Why Recycled Content is Dominating Medium: An Insightful Look

Explore the reasons behind the prevalence of recycled content on Medium and how it affects writers and readers alike.

Catalyzing Change: The Essence of Inspiring Leadership

Explore the qualities of Inspiring Leaders and their transformative impact on society.

Drinks to Combat Diabetes Risk This Summer

Discover five refreshing drinks that can help reduce diabetes risk while keeping you hydrated this summer.