# -*- coding: utf-8 -*-
"""
================================================================================
Comprehensive Python Guide: Data Types, Operations, and I/O
================================================================================
This program provides an in-depth demonstration of Python's fundamental concepts.
It is structured into sections, each focusing on a specific data type.
Within each section, we will:
1. Demonstrate how to create variables of that type.
2. Explore all relevant operations (arithmetic, comparison, logical, etc.).
3. Showcase common built-in functions and methods.
The final section covers basic Input/Output (I/O) operations.
"""
# A function to print section headers for better readability.
def print_header(title):
"""Prints a formatted header to the console."""
print("\n" + "="*60)
print(f"| {title.center(56)} |")
print("="*60)
# ==============================================================================
# SECTION 1: NUMERIC TYPES (int, float, complex)
# ==============================================================================
# ------------------------------------------------------------------------------
# 1.1: Integers (int)
# ------------------------------------------------------------------------------
print_header("Integers (int)")
a_int = 10
b_int = 3
print(f"Initial Integers: a = {a_int}, b = {b_int}")
print(f"Type of 'a_int' is: {type(a_int)}")
# Arithmetic Operations
print("\n--- Arithmetic Operations ---")
print(f"Addition (a + b): {a_int + b_int}")
print(f"Subtraction (a - b): {a_int - b_int}")
print(f"Multiplication (a * b): {a_int * b_int}")
print(f"Division (a / b): {a_int / b_int} (Always results in a float)")
print(f"Floor Division (a // b): {a_int // b_int} (Discards the fractional part)")
print(f"Modulus (a % b): {a_int % b_int} (Remainder of the division)")
print(f"Exponentiation (a ** b): {a_int ** b_int} (a to the power of b)")
# Comparison Operations
print("\n--- Comparison Operations ---")
print(f"Is a == b? {a_int == b_int}")
print(f"Is a != b? {a_int != b_int}")
print(f"Is a > b? {a_int > b_int}")
print(f"Is a < b? {a_int < b_int}")
print(f"Is a >= b? {a_int >= b_int}")
print(f"Is a <= b? {a_int <= b_int}")
# ------------------------------------------------------------------------------
# 1.2: Floating-Point Numbers (float)
# ------------------------------------------------------------------------------
print_header("Floating-Point Numbers (float)")
a_float = 10.5
b_float = 3.5
print(f"Initial Floats: a = {a_float}, b = {b_float}")
print(f"Type of 'a_float' is: {type(a_float)}")
# Arithmetic Operations (same as int, but with floats)
print("\n--- Arithmetic Operations ---")
print(f"Addition (a + b): {a_float + b_float}")
print(f"Subtraction (a - b): {a_float - b_float}")
print(f"Multiplication (a * b): {a_float * b_float}")
print(f"Division (a / b): {a_float / b_float}")
# Built-in functions
print("\n--- Built-in Functions ---")
print(f"Rounding 10.56789 to 2 decimal places: {round(10.56789, 2)}")
print(f"Converting float to int (truncates): {int(a_float)}")
# ------------------------------------------------------------------------------
# 1.3: Complex Numbers (complex)
# ------------------------------------------------------------------------------
print_header("Complex Numbers (complex)")
a_complex = 2 + 3j
b_complex = 1 - 1j
print(f"Initial Complex Numbers: a = {a_complex}, b = {b_complex}")
print(f"Type of 'a_complex' is: {type(a_complex)}")
# Arithmetic Operations
print("\n--- Arithmetic Operations ---")
print(f"Addition (a + b): {a_complex + b_complex}")
print(f"Subtraction (a - b): {a_complex - b_complex}")
print(f"Multiplication (a * b): {a_complex * b_complex}")
print(f"Division (a / b): {a_complex / b_complex}")
# Accessing parts
print("\n--- Accessing Parts ---")
print(f"Real part of a: {a_complex.real}")
print(f"Imaginary part of a: {a_complex.imag}")
print(f"Conjugate of a: {a_complex.conjugate()}")
# ==============================================================================
# SECTION 2: SEQUENCE TYPES (str, list, tuple)
# ==============================================================================
# ------------------------------------------------------------------------------
# 2.1: Strings (str) - Immutable sequence of characters
# ------------------------------------------------------------------------------
print_header("Strings (str)")
my_string = " Hello, Python World! "
print(f"Initial String: '{my_string}'")
print(f"Type is: {type(my_string)}")
# Indexing and Slicing
print("\n--- Indexing and Slicing ---")
print(f"First character (index 2): '{my_string[2]}'")
print(f"Last character (index -1): '{my_string[-1]}'")
print(f"Slice from index 2 to 7: '{my_string[2:7]}'") # 'Hello'
print(f"Slice from start to index 7: '{my_string[:7]}'")
print(f"Slice from index 9 to end: '{my_string[9:]}'")
# String Operations
print("\n--- Basic Operations ---")
print(f"Length of string: {len(my_string)}")
print(f"Concatenation: 'First' + ' ' + 'Part'")
print("Repetition: " + "'Ha' * 3")
# String Methods
print("\n--- Common String Methods ---")
print(f"Uppercase: '{my_string.upper()}'")
print(f"Lowercase: '{my_string.lower()}'")
print(f"Strip whitespace: '{my_string.strip()}'")
print(f"Replace 'Python' with 'Dev': '{my_string.replace('Python', 'Developers')}'")
print(f"Split by ',': {my_string.split(',')}")
print(f"Starts with ' Hello': {my_string.startswith(' Hello')}")
print(f"Ends with 'World! ': {my_string.endswith('World! ')}")
# Membership testing
print("\n--- Membership (in / not in) ---")
print(f"Is 'Python' in the string? {'Python' in my_string}")
print(f"Is 'Java' not in the string? {'Java' not in my_string}")
# ------------------------------------------------------------------------------
# 2.2: Lists (list) - Mutable, ordered sequence of items
# ------------------------------------------------------------------------------
print_header("Lists (list)")
my_list = [1, "apple", 3.14, "apple", True]
print(f"Initial List: {my_list}")
print(f"Type is: {type(my_list)}")
# Indexing and Slicing (works like strings)
print("\n--- Indexing and Slicing ---")
print(f"Element at index 1: {my_list[1]}")
print(f"Slice from index 1 to 3: {my_list[1:3]}")
# Modifying a list (it's mutable)
print("\n--- Modifying a List ---")
my_list[0] = "one"
print(f"After changing index 0: {my_list}")
my_list.append("new_item")
print(f"After appending 'new_item': {my_list}")
my_list.insert(2, "inserted")
print(f"After inserting at index 2: {my_list}")
removed_item = my_list.pop(3) # Removes and returns item at index 3
print(f"After popping index 3: {my_list} (Removed: {removed_item})")
my_list.remove("one") # Removes the first occurrence of 'one'
print(f"After removing 'one': {my_list}")
# List Operations
numbers = [5, 1, 9, 3]
print(f"\n--- List Operations on {numbers} ---")
numbers.sort()
print(f"Sorted list (in-place): {numbers}")
numbers.reverse()
print(f"Reversed list (in-place): {numbers}")
print(f"Count of 'apple' in my_list: {my_list.count('apple')}")
print(f"Length of my_list: {len(my_list)}")
# ------------------------------------------------------------------------------
# 2.3: Tuples (tuple) - Immutable, ordered sequence of items
# ------------------------------------------------------------------------------
print_header("Tuples (tuple)")
my_tuple = (1, "apple", 3.14, "apple", True)
print(f"Initial Tuple: {my_tuple}")
print(f"Type is: {type(my_tuple)}")
print("NOTE: Tuples are immutable. You cannot change, add, or remove elements after creation.")
# Trying to change a tuple will cause an error:
# my_tuple[0] = "one" # This would raise a TypeError
# Operations are mostly non-modifying
print("\n--- Tuple Operations ---")
print(f"Element at index 1: {my_tuple[1]}")
print(f"Slice from index 1 to 3: {my_tuple[1:3]}")
print(f"Count of 'apple': {my_tuple.count('apple')}")
print(f"Index of first 'apple': {my_tuple.index('apple')}")
print(f"Length of tuple: {len(my_tuple)}")
# Tuple unpacking
print("\n--- Tuple Unpacking ---")
a, b, c, d, e = my_tuple
print(f"Unpacked variables: a={a}, b={b}, c={c}, d={d}, e={e}")
# ==============================================================================
# SECTION 3: MAPPING TYPE (dict)
# ==============================================================================
print_header("Dictionaries (dict)")
# A collection of key-value pairs. Unordered (in older Python versions), mutable.
my_dict = {
"name": "Alice",
"age": 30,
"city": "New York",
"is_student": False
}
print(f"Initial Dictionary: {my_dict}")
print(f"Type is: {type(my_dict)}")
# Accessing and Modifying
print("\n--- Accessing and Modifying ---")
print(f"Get value for key 'name': {my_dict['name']}")
my_dict['age'] = 31 # Update a value
print(f"After updating age: {my_dict}")
my_dict['country'] = 'USA' # Add a new key-value pair
print(f"After adding country: {my_dict}")
# Removing items
print("\n--- Removing Items ---")
removed_value = my_dict.pop('city')
print(f"After popping 'city': {my_dict} (Removed: {removed_value})")
# Dictionary Methods
print("\n--- Dictionary Methods ---")
print(f"All keys: {my_dict.keys()}")
print(f"All values: {my_dict.values()}")
print(f"All key-value pairs (items): {my_dict.items()}")
# .get() is a safe way to access a key, returns None if key doesn't exist
print(f"Safely get 'name': {my_dict.get('name')}")
print(f"Safely get 'zip_code': {my_dict.get('zip_code')}")
# ==============================================================================
# SECTION 4: SET TYPES (set, frozenset)
# ==============================================================================
# ------------------------------------------------------------------------------
# 4.1: Sets (set) - Unordered collection of UNIQUE items. Mutable.
# ------------------------------------------------------------------------------
print_header("Sets (set)")
my_set = {1, 2, 3, 4, 4, 5, 5} # Duplicates are automatically removed
print(f"Initial Set (duplicates removed): {my_set}")
print(f"Type is: {type(my_set)}")
# Modifying a set
print("\n--- Modifying a Set ---")
my_set.add(6)
print(f"After adding 6: {my_set}")
my_set.add(1) # Adding an existing element does nothing
print(f"After adding 1 again: {my_set}")
my_set.remove(3) # Raises KeyError if element not found
print(f"After removing 3: {my_set}")
my_set.discard(10) # Does NOT raise an error if element not found
print(f"After discarding 10 (no error): {my_set}")
# Set Operations
print("\n--- Set Operations ---")
set_a = {1, 2, 3, 4}
set_b = {3, 4, 5, 6}
print(f"Set A: {set_a}")
print(f"Set B: {set_b}")
print(f"Union (A | B): {set_a | set_b}")
print(f"Intersection (A & B): {set_a & set_b}")
print(f"Difference (A - B): {set_a - set_b}")
print(f"Symmetric Difference (A ^ B):{set_a ^ set_b}")
# ------------------------------------------------------------------------------
# 4.2: Frozen Sets (frozenset) - An immutable version of a set.
# ------------------------------------------------------------------------------
print_header("Frozen Sets (frozenset)")
my_frozenset = frozenset([1, 2, 3, 4, 4])
print(f"Initial Frozen Set: {my_frozenset}")
print(f"Type is: {type(my_frozenset)}")
print("NOTE: Frozen sets are immutable. You cannot add or remove elements.")
# my_frozenset.add(5) # This would raise an AttributeError
# Set operations still work and return a new set or frozenset.
print(f"Union with {{3, 4, 5, 6}}: {my_frozenset.union({3, 4, 5, 6})}")
# ==============================================================================
# SECTION 5: BOOLEAN TYPE (bool)
# ==============================================================================
print_header("Booleans (bool)")
is_active = True
is_admin = False
print(f"Initial Booleans: is_active={is_active}, is_admin={is_admin}")
print(f"Type is: {type(is_active)}")
# Logical Operations
print("\n--- Logical Operations ---")
print(f"is_active and is_admin: {is_active and is_admin}")
print(f"is_active or is_admin: {is_active or is_admin}")
print(f"not is_active: {not is_active}")
# Booleans in numeric contexts: True is 1, False is 0
print("\n--- Booleans in Numeric Context ---")
print(f"True + 5: {True + 5}")
print(f"False * 10: {False * 10}")
# ==============================================================================
# SECTION 6: INPUT AND OUTPUT (I/O)
# ==============================================================================
print_header("Input and Output (I/O)")
# --- Output ---
print("\n--- Output Operations ---")
print("This is a simple print statement.")
name = "Bob"
age = 42
# Using an f-string (formatted string literal) - the modern, preferred way
print(f"Hello, my name is {name} and I am {age} years old.")
# Using the .format() method
print("Hello, my name is {} and I am {} years old.".format(name, age))
# --- Input ---
print("\n--- Input Operations ---")
print("The program will now ask for your input.")
# The input() function always returns a string
user_name = input("Please enter your name: ")
print(f"Hello, {user_name}! It's nice to meet you.")
print(f"The data type of your input is: {type(user_name)}")
# To perform math, you must convert the input string to a number
user_age_str = input("Please enter your age: ")
try:
# We use a try-except block to handle cases where the user
# might not enter a valid number.
user_age_int = int(user_age_str)
print(f"In 10 years, you will be {user_age_int + 10} years old.")
print(f"The data type of your age is now: {type(user_age_int)}")
except ValueError:
print(f"'{user_age_str}' is not a valid number. Could not calculate future age.")
print("\n" + "="*60)
print("DEMONSTRATION COMPLETE".center(60))
print("="*60)