Skip to content

Latest commit

 

History

History
617 lines (415 loc) · 19.6 KB

12.Imports.md

File metadata and controls

617 lines (415 loc) · 19.6 KB

Lesson 12: Imports

"Where Python's Collaborative Symphony Begins."

Content

  1. Introduction
  2. Creating a Module
  3. import, from, and as
  4. if __name__ == "__main__"
  5. Packages
  6. venv
  7. requests
  8. Pillow
  9. Choose your direction
  10. Homework

1. Introduction

A Python module is essentially a file that contains definitions and statements.

The module name is the same as the file name with the .py extension added at the end.

1.1 Why do we need modules?

Generally, if we were to write everything into one file, we wouldn't be able to maintain our application, making it hard for other developers to use.

Using modules helps us to do the following:

  • Organizing Code: By dividing a program into modules you can separate parts and concerns making it easier to manage and understand the program.

  • Reusable Components: Functions, classes and variables defined in a module can be easily reused across sections of a program or different programs.

  • Managing Namespaces: Modules help prevent conflicts between names by providing a separate namespace, for each module.

2. Creating a Module

In Python, a simple .py file can be considered and used as a module to store specific variables, functions, runnable code or any other object, which can then be used in other modules.

  1. Create a Python File: Start by creating a Python file. For instance, name it mymodule.py.

  2. Add Code to the File: Write the necessary functions, classes, and variables in the file. Here’s an example of what mymodule.py might look like:

def say_hello(name):
    print(f"Hello, {name}!")

def addition(a, b):
    return a + b

variable = 123

NOTE: Module names should conform to Python’s naming conventions. They should be short, lowercase, and if necessary, use underscores to improve readability.

Example

Let's create a mini application stored in assets/lesson_12/ directory.

We will split our logic having different .py files:

└── lesson_12               
    ├── calculations.py         
    ├── greetings.py           
    ├── main.py
    └── menu.py

NOTE: Include docstrings and comments to explain what your module does, the purpose of different functions, expected parameter types, return types, and so on.

Example

"""
This modules provides several functions which interact with arithmetical operations between 2 numbers
"""

def add(a, b):
    """Return the sum of a and b."""
    return a + b

def subtract(a, b):
    """Return the difference between a and b."""
    return a - b

def multiply(a, b):
    """Return the product of a and b."""
    return a * b

def divide(a, b):
    """Return the quotient of a divided by b. Raises ValueError on division by zero."""
    if b == 0:
        raise ValueError("Cannot divide by zero.")
    return a / b

Again, instead of having everything in a one file, we created a couple of different files where each serves its purpose.

2.3 How to?

Break down your application into logical components. Each component should have a well-defined responsibility.

For example, user authentication, data processing, and user interface components can be separate modules.

  • Repeated Code: If you find yourself copying and pasting the same code across multiple parts of your project, it's a sign that you should modularize this code.

  • Reusable Components: If your project contains components that could be reused across different parts of the application or even in different projects, these components are good candidates for modularization.

Don't get stuck or overthink how to do it in the best possible way, everything will come with practice.

3. import, from, and as

Python provides several ways to bring in external modules into your current script, each serves different needs and providing various ways to access the module's components.

3.1 import

Basic Import: Use the import statement to bring an entire module into your script. This way, you access the module's components using the dot notation, which helps in maintaining their namespace.

import mymodule

mymodule.say_hello("Alice")  # Calls the say_hello function from mymodule
result = mymodule.addition(10, 20)  # Calls the addition function from mymodule
print(mymodule.variable)  # Access the variable from mymodule

3.2 from

Import Specific Components: You can choose to import specific components (functions, classes, or variables) from a module. This is useful when you only need a part of the module.

from mymodule import say_hello, addition

say_hello("Bob")  # Directly use the imported function
result = addition(5, 15)  # Directly use the imported function

Note: Generally, it is a preferable way, as very often we don't need to import everything

Importing All Components: Using from module import * imports all public names from the module into the current namespace.

from mymodule import *

NOTE: It's generally discouraged as it can lead to conflicts with existing names and makes it unclear which names are present in the current namespace.

3.3 Module Aliasing with as

Aliasing Modules: If a module name is long or likely to conflict with an existing name in your code, you can give it an alias. This allows you to reference it with a different name.

import mymodule as mm

mm.say_hello("Carol")  # Use the alias to call a function from mymodule

Aliasing Specific Components: You can also alias specific components when you import them.

from mymodule import say_hello as greet

greet("Dave")  # Use the alias to call the imported function

3.3.1 Why Aliasing?

For example, let's say you are trying to import a function time from two different modules.

The only way you can achieve this without causing conflicts within the code is by using aliasing.

Example

from x import time as x_time
from y import time as y_time

Explanation

Thanks to as you can use time from both x and y modules, without any conflicts and be able to distinct them too.

4. if __name__ == "__main__"

When writing Python scripts, you'll often see a code block guarded by at the bottom:

if __name__ == "__main__"

The special __name__ attribute is set to __main__ when a script is executed directly.

However, when the same script is imported as a module in another script, __name__ is set to the script's filename.

Example

Consider the script mymodule.py, which defines a function and is executed:

# mymodule.py

def say_hello(name):
    """Print a greeting to the named individual."""
    print(f"Hello, {name}!")

def main():
    """Run the main logic of the script."""
    say_hello("Alice")

# This condition checks if the script is the entry point to the program
if __name__ == "__main__":
    main()  # Only runs if the script is executed, not if it's imported.

Explanation

If mymodule.py is run as the main file, the main() function will execute and Alice will be greeted.

If mymodule.py is imported into another file, say_hello can be used, but Alice will not be greeted until say_hello is explicitly called.

Try it yourself and experiment with the code provided in assets/lesson_12, and you will see the diference.

5. Packages

Packages allow you to group related modules under a common namespace, making it easier to understand and manage the code.

They help in avoiding conflicts between module names and provide a structured way to access the functions, classes, and variables defined in different modules.

5.1 __init__.py

The __init__.py file is a key ingredient in Python packages. It serves multiple roles:

  • Initialization: Executes any code necessary to set up the package's state or initialize certain variables.
  • Namespace Management: Declares which modules or symbols the package exports as the API, through __all__.
  • Hierarchy Signaling: Signifies to Python that the directory should be treated as a package, allowing modules to be imported from it.

Instead of raw theory, let's take a look at the real application and try to come up with a good structure for better maintainability of the codebase

Example

Consider a package named finance designed to handle various financial calculations and data processing

Strucure

finance/
    __init__.py
    calculator.py
    taxes.py
    investments/
        __init__.py
        stocks.py
        bonds.py

finance/__init__.py

# Specify the public API for convenience
__all__ = ['calculator', 'taxes', 'investments']

# You may also initialize some package-wide constants or setup code, though its not a common practice nowdays
DEFAULT_TAX_BRACKET = '25%'

finance/calculator.py

def calculate_interest(principal, rate, time):
    """Compute interest earned on a principal over time at a fixed rate."""
    return principal * (rate / 100) * time

finance/taxes.py

from .calculator import calculate_interest

def calculate_tax_due(income, rate=DEFAULT_TAX_BRACKET):
    """Calculate the tax owed based on income and a tax rate."""
    pass

finance/investments/stocks.py

def analyze_stock_market():
    """Perform analysis on stock market trends."""
    pass

5.2 Utilizing Sub-Packages

Sub-packages enable even more granular organization within a package, grouping together related modules.

For instance, finance/investments is a sub-package grouping financial investment-related modules like stocks.py and bonds.py.

When the project becomes extremely big, think about how you could re-structure to make it more maintainable, reusable and readable.

5.3 Importing from Packages

Importing from packages or sub-packages is done with a .dot notation, allowing you to use specific functions or entire modules.

Examples:

# Importing a specific function from a module within the 'finance' package
from finance.calculator import calculate_interest

# Importing an entire module from a sub-package
from finance.investments import stocks

# Using the imported function
interest = calculate_interest(1000, 5, 3)  # Calculate interest on $1000 at 5% for 3 years

# Invoking a function from the imported 'stocks' module
stocks.analyze_stock_market()

6. venv

Python’s virtual environments allow you to install and manage Python packages in an isolated environment.

Suppose we need to install a couple of external packages, which provide interfaces to carry out some specific tasks and resolve issues while it can't be done with a default Python functionality.

That's where virtual environments and external packages come in handy.

6.1 Benefits of Using venv

  • Dependency Management: Keep project-specific dependencies in separate environments.
  • Project Isolation: Avoid installing packages globally, which can lead to version conflicts.
  • Reproducibility: Create an environment that can easily be replicated on other machines or deployments.

The purpose of venv is to ensure that each project has its own set of dependencies, which may differ in version from one project to another, without causing conflicts.

IMPORTANT: We could install everything globally, but such behaviour leads to conflicts among projects, and is not recomended at all.

6.2 Creating a Virtual Environment

You can create a virtual environment using the venv module that comes with Python 3.x.

  1. Setup: Navigate to your project’s directory:

    cd my_project
  2. Creation: Run the following command to create a virtual environment named venv:

    python3 -m venv venv

Note: You can replace venv with your preferred environment name.

  1. Activation: Run the following commands
  • On Windows:

    .\venv\Scripts\activate
  • On macOS and Linux:

    source venv/bin/activate

When activated, the name of the virtual environment (venv) will appear in your shell prompt, indicating that all python and pip commands are now scoped to the venv.

NOTE: Create a new virtual environment for each project to keep dependencies separate.

6.3 Managing Packages with pip

With an activated virtual environment, you can use pip to install, upgrade, and remove packages. Essentially, pip is a package manager which helps you to install the external dependencies from PyPi.

  • Installing Packages:
    pip install package_name
  • Listing Installed Packages:
    pip list
  • Uninstalling Packages:
    pip uninstall package_name

As well, you can run pip --help if you want to do anything other with venv inside your project.

Let's take a look at the couple of interesting modules in the sections below.

7. requests

The requests module is a Python HTTP library that simplifies making network requests. It’s known for its ease of use and user-friendly interface.

7.1 Installation

Before you can use requests, you'll need to create venv, activate and install requests into it.

python3 -m venv venv
source venv/bin/activate
pip install requests

Let's create an application and split everything into diffrent modules as it was already discussed above.

7.2 Weather Fetcher App

Objective:: Develop an application to display real-time weather information based on user input.

NOTE: The application will interact with the OpenWeatherMap API to obtain data for the specified city and present it to the user in a clear and concise format.

Structure

weather_fetcher/
├── fetch.py
├── display.py
├── main.py
└── constants.py

constants.py

# Store configuration constants
BASE_URL = "http://api.openweathermap.org/data/2.5/weather"
API_KEY = "your_api_key_here"  # Replace with your actual OpenWeatherMap API key

fetch.py

# Contains the logic for fetching weather data from OpenWeatherMap API
import requests
from .constants import BASE_URL, API_KEY  # Ensure proper relative import

def get_weather_data(city):
    """Fetch weather data for a given city."""
    params = {
        'q': city,
        'appid': API_KEY,
        'units': 'metric'
    }
    response = requests.get(BASE_URL, params=params)
    if response.status_code == 200:
        return response.json()
    else:
        response.raise_for_status()

display.py

# Contains the logic for displaying the fetched weather data
def display_weather(data):
    """Display the weather information."""
    city = data['name']
    temp = data['main']['temp']
    description = data['weather'][0]['description']
    humidity = data['main']['humidity']
    
    print(f"Weather in {city}:")
    print(f"Temperature: {temp}°C")
    print(f"Condition: {description}")
    print(f"Humidity: {humidity}%")

main.py

# Entry point for the Weather Fetcher application
from fetch import get_weather_data
from display import display_weather

def main():
    city = input("Enter the name of the city to get the weather for: ")
    try:
        weather_data = get_weather_data(city)
        display_weather(weather_data)
    except requests.exceptions.HTTPError as err:
        print("HTTP error occurred: ", err)
    except requests.exceptions.RequestException as err:
        print("Request error occurred: ", err)

if __name__ == "__main__":
    main()

You can find the whole project in assets/weather_fetcher directory.

8. Pillow

Pillow is a fork of the Python Imaging Library (PIL) which adds image processing capabilities to your Python interpreter.

8.2 Installation

Install the library in your virtual environment, same as we did with requests library:

python3 -m venv venv
source venv/bin/activate
pip install Pillow

8.3 Image Operations App

Objective: Develop an application will perform basic operations on an image, such as opening, displaying, rotating, and cropping.

Structure

image_processor/
├── processor.py
└── main.py

processor.py

from PIL import Image

def open_image(path):
    """Open and return an image."""
    return Image.open(path)

def show_image(image):
    """Display the image."""
    image.show()

def rotate_image(image, degrees):
    """Rotate the image by a certain number of degrees."""
    return image.rotate(degrees)

def crop_image(image, box):
    """Crop the image to a specific box and return the cropped image."""
    return image.crop(box)

main.py

from processor import open_image, show_image, rotate_image, crop_image

def main():
    image_path = input("Enter the path to the image: ")
    image = open_image(image_path)
    show_image(image)

    rotated = rotate_image(image, 90)
    show_image(rotated)

    cropped = crop_image(image, (100, 100, 400, 400))
    show_image(cropped)

if __name__ == "__main__":
    main()

You can find the whole project in assets/image_processor directory.

Add functionality for saving image and applying filters and effects to it.

9. Choose your direction

It's time that you decide your career path and who you want to become in the future. Now you have a general idea about programming and you need to research more information and decide the future direction of your career.

I can recommend a several libraries to look into for Data Science and Web Development.

Data Science (DS):

  • Pandas: Data manipulation and analysis.
  • NumPy: Numerical computing with powerful array objects.
  • Matplotlib & Seaborn: Data visualization.
  • Scikit-learn: Machine learning.
  • TensorFlow & PyTorch: Deep learning.

Web Development (Backend):

  • Django & Flask: Web frameworks for building web applications.
  • FastAPI: Modern, fast web framework for building APIs.
  • SQLAlchemy: Database toolkit and ORM.
  • Celery: Asynchronous task queue/job queue.
  • Redis & Memcached: Caching systems to enhance performance.

Thanks for attention! Happy Restructuring!

10. Homework

During this howemork I would like you to google. It's an extremely important skill for a programmer, which we use on a daily basis.

Disclaimer: Sometimes people can give you tasks which you don't know how to accomplish, there are a couple of unknown words (libs) below. Good luck!

Task 1: My Gallery

Objective: Build a Python application that generates an HTML image gallery from a folder of image files.

Requirements:

  • Create a virtual environment and install Pillow for image processing.
  • Create a module to resize images to thumbnails using Pillow.
  • Ensure images maintain their aspect ratio.
  • Write a module to generate an HTML file that displays all thumbnails as clickable links to the original images.
  • Implement a command-line interface where the user can specify the folder containing images and the output directory for the HTML gallery.

Task 2: CLI Task Manager

Objective: Create a command-line interface (CLI) task manager application that allows users to add, list, and delete tasks.

Requirements:

  • Create a virtual environment and install Pillow for image processing.
  • Enable users to add new tasks, mark tasks as completed, list all tasks, and delete tasks through command-line arguments.
  • Use the argparse or click library to handle command-line arguments for different operations (e.g., --add, --complete, --list, --delete).