Skip to main content

Command Palette

Search for a command to run...

Exploring Python Concepts with One Program

Updated
5 min readView as Markdown
Exploring Python Concepts with One Program
G

I'm passionate about coding and enjoy working with embedded systems, app development, and compiler design.

While learning Python, I noticed that most examples explain only one concept at a time. To understand how different features work together, I wrote a small program that combines multiple Python topics into a single example. Even though the program is simple, it demonstrates asynchronous programming, decorators, generators, tasks, user input, and concurrency.

In this blog, I'll explain each concept used in the program and how they interact with each other.

Program Overview

The main goal of this program is to perform two tasks simultaneously:

  • Generate Fibonacci numbers.

  • Ask the user for their name and modify the output using a decorator.

Instead of executing these tasks one after another, they run concurrently using Python's asyncio library.


1. Decorators

The first concept used is a decorator.

def fake(func):
    async def change(*args, **kwargs):
        res = await func(*args, **kwargs)
        res = "Crazy " + res
        return res
    return change

A decorator allows us to modify the behavior of another function without changing its original code.

Here, the fake decorator wraps the hello() function. Whatever name the user enters gets modified by adding the word "Crazy" before returning it.

For example:

Input: Gagan
Output: Crazy Gagan

This is a simple example of how decorators can add extra functionality while keeping the original function clean.


2. Asynchronous Functions

The program uses asynchronous functions with the async keyword.

@fake
async def hello():

and

async def fibo():

An asynchronous function doesn't immediately execute everything line by line. Instead, it can pause whenever it reaches an await statement and allow another task to run during that time.

This helps when dealing with operations that take time, such as waiting for user input or network requests.


3. Using await

Inside the program, await appears several times.

he = await asyncio.to_thread(input, "Enter your name:")

Normally, input() blocks the entire program until the user types something. Since input() is not asynchronous, I used asyncio.to_thread() to run it in a separate thread so that it doesn't stop other asynchronous tasks.

Another example is

await asyncio.sleep(0.1)

Unlike time.sleep(), this pauses only the current coroutine instead of blocking the whole program.

Similarly,

await asyncio.sleep(3)

inside fibo() delays Fibonacci generation without freezing the event loop.


4. Generators

The Fibonacci sequence is generated using a generator function.

def fib(n):
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

Instead of storing all Fibonacci numbers in a list, the generator produces one value at a time using the yield keyword.

This is memory-efficient because only one number exists in memory during each iteration.

The generator is later used like this:

for num in fib(10):
    print(num)

which prints the first ten Fibonacci numbers.


5. Creating Tasks

Inside main(), I created two asynchronous tasks.

task1 = asyncio.create_task(fibo())
task2 = asyncio.create_task(hello())

create_task() schedules both coroutines to run concurrently.

Without create_task(), the program would wait for one coroutine to finish before starting the other.


6. Waiting for Tasks

The results are collected using

ans1 = await task1
ans2 = await task2

await pauses only until the specific task finishes and returns its value.

Later, I also used

res = await asyncio.gather(fibo(), hello())

asyncio.gather() executes multiple coroutines together and returns all their results in a list.

This is useful when we want to wait for several asynchronous operations simultaneously.


7. Event Loop

The program starts with

if __name__ == "__main__":
    asyncio.run(main())

asyncio.run() creates the event loop, executes the main() coroutine, and closes the loop after completion.

The event loop is responsible for scheduling and switching between asynchronous tasks whenever they reach an await statement.


8. Return Values

The two asynchronous functions return different values.

hello() returns the modified username after passing through the decorator.

fibo() prints the Fibonacci sequence and returns the last generated number.

Finally,

print(ans1, ans2, "async tasks performed", res)

prints the results obtained from both tasks.


Concepts Covered

This single program demonstrates several important Python topics:

  • Decorators

  • Asynchronous programming (async and await)

  • asyncio.create_task()

  • asyncio.gather()

  • Event loop using asyncio.run()

  • Running blocking functions with asyncio.to_thread()

  • Generators and the yield keyword

  • Fibonacci sequence generation

  • Concurrent execution of multiple tasks

import time
import asyncio
import functools
def fake(func):
    async def change(*args,**kwargs):
        res=await func(*args,**kwargs)
        res="Crazy"+" "+res
        return res
    return change

@fake
async def hello():
    he=await asyncio.to_thread(input,"Enter your name:")
    await asyncio.sleep(0.1)
    #he="Yello"
    return he



def fib(n):
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

async def fibo():
    await asyncio.sleep(3)
    nun=0
    for num in fib(10):
        print(num)

    return num



async def main():
    task1=asyncio.create_task(fibo())
    task2=asyncio.create_task(hello())
    ans1=await task1
    ans2=await task2
    res=await asyncio.gather(fibo(),hello())
    print(ans1,ans2,"async tasks performed",res)


if __name__=="__main__":
    asyncio.run(main())

What I Learned

Writing this program helped me understand that asynchronous programming is not just about making code faster—it is about using waiting time efficiently. While one task is waiting for input or sleeping, another task can continue executing. Combining decorators, generators, and asynchronous functions in the same program also showed me how different Python features can work together in a practical example.

Happy Coding...

3 views