Interactive Python Book

Variables & Data Types

The basic building blocks of any Python program.

Understanding Variables

In Python, a variable is a name you assign to a value. Think of it as a label for a box. You don't need to declare its type; Python figures it out automatically (this is called "dynamic typing").

# A variable 'name' storing a string
name = "Alice"

# A variable 'age' storing an integer
age = 30

# You can change the value and type
age = "Thirty"
Common Data Types

Python has several built-in data types:

  • Text: str (e.g., "Hello")
  • Numeric: int (10), float (10.5)
  • Sequence: list, tuple
  • Mapping: dict
  • Set: set
  • Boolean: bool (True, False)
x_str = "Hello"       # str
x_int = 20            # int
x_float = 20.5          # float
x_list = ["apple", "banana"] # list
x_tuple = ("apple", "banana") # tuple
x_dict = {"name": "John"}  # dict
x_bool = True          # bool

Control Flow

How to make decisions and repeat actions in your code.

Conditionals (if, elif, else)

Conditionals allow your program to execute certain blocks of code only if a condition is met.

temperature = 25

if temperature > 30:
    print("It's a hot day!")
elif temperature > 20:
    print("It's a pleasant day.")
else:
    print("It's cold.")
For Loops

A for loop is used for iterating over a sequence (like a list, tuple, dictionary, set, or string).

fruits = ["apple", "banana", "cherry"]

# Loop through each item in the list
for fruit in fruits:
    print(fruit)

# Loop a specific number of times
for i in range(5):
    print(i)  # Prints 0, 1, 2, 3, 4
While Loops

A while loop executes a set of statements as long as a condition is true.

count = 0
while count < 5:
    print(count)
    count += 1  # Don't forget to increment!

Functions

Reusable blocks of code that perform a specific task.

Defining Functions

Functions are defined using the def keyword. They can take inputs (called "arguments") and produce an output (using the return keyword).

# A simple function with no arguments
def greet():
    print("Hello, world!")

# Call the function
greet()
Arguments & Return Values

Pass data into functions as arguments and get data back using return.

def add_numbers(num1, num2):
    total = num1 + num2
    return total

# Call the function and store the result
sum_result = add_numbers(5, 10)
print(sum_result)  # Output: 15
Lambda Functions

A lambda function is a small, anonymous function. It can take any number of arguments, but can only have one expression.

# A lambda function that adds 10
x = lambda a : a + 10
print(x(5))  # Output: 15

# A lambda function with two arguments
multiply = lambda a, b : a * b
print(multiply(6, 7)) # Output: 42

Data Structures

How to organize and store collections of data efficiently.

Lists

Lists are ordered, mutable (changeable), and allow duplicate members. Defined with [].

my_list = ["apple", "banana", "cherry"]
my_list.append("orange")
print(my_list[1]) # Output: banana
Dictionaries

Dictionaries store data in key:value pairs. They are ordered (as of Python 3.7), mutable, and do not allow duplicate keys. Defined with {}.

person = {
    "name": "John",
    "age": 30,
    "city": "New York"
}
print(person["age"]) # Output: 30
person["email"] = "john@example.com"
Tuples and Sets

Tuples: Ordered and immutable (unchangeable). Defined with (). Used for data you don't want to change.

Sets: Unordered, mutable, and do not allow duplicate members. Defined with {}. Used for mathematical set operations (union, intersection).

# A tuple
my_tuple = ("red", "green", "blue")
# my_tuple[0] = "yellow"  <-- This will raise an error!

# A set (duplicates are removed)
my_set = {"a", "b", "c", "a"}
print(my_set) # Output: {'c', 'b', 'a'}

Object-Oriented Programming

A programming paradigm based on "objects" and "classes".

Classes and Objects

A class is a blueprint for creating objects. An object is an instance of a class.

The __init__ method is a special "dunder" method that runs when an object is created. self refers to the object instance itself.

class Dog:
    # The "constructor" method
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # A "method" (a function inside a class)
    def bark(self):
        return f"Woof! My name is {self.name}"

# Create an 'object' (instance) of the Dog class
my_dog = Dog("Buddy", 3)
print(my_dog.name)     # Output: Buddy
print(my_dog.bark()) # Output: Woof! My name is Buddy
Inheritance

Inheritance allows a new class (child class) to inherit attributes and methods from an existing class (parent class).

# Parent class
class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        raise NotImplementedError("Subclass must implement abstract method")

# Child class (inherits from Animal)
class Cat(Animal):
    def speak(self):
        return f"{self.name} says Meow!"

# Child class (inherits from Animal)
class Dog(Animal):
    def speak(self):
        return f"{self.name} says Woof!"

fluffy = Cat("Fluffy")
buddy = Dog("Buddy")

print(fluffy.speak())
print(buddy.speak())

Advanced Concepts

Topics for building complex and efficient applications.

Decorators

Decorators are a powerful way to modify or extend the behavior of a function without permanently changing its source code. They are "functions that take another function as an argument, add some functionality, and return another function."

# This is the decorator function
def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

# Use the @ symbol to "decorate" the function
@my_decorator
def say_hello():
    print("Hello!")

say_hello()
Asyncio (async/await)

asyncio is used for asynchronous programming. The async and await syntax allows you to write concurrent code that looks and behaves like synchronous code, making it easier to manage tasks that involve waiting (like I/O operations).

import asyncio

async def main():
    print('Hello')
    await asyncio.sleep(1) # Pause here, let other tasks run
    print('...world!')

async def other_task():
    print('This runs concurrently!')

# In a real script, you'd run the main coroutine
# asyncio.run(main())
print("Note: Run 'asyncio.run(main())' in a .py file")