# Get input from the user for two grades.
# `float()` converts the text input into a number with decimal points.
grade1 = float(input("Input first grade (0-10):"))
grade2 = float(input("Input second grade (0-10):"))
# Get input for the number of absences and total classes.
# `int()` converts the text input into a whole number.
absences = int(input("Input number of absences:"))
total_classes = int(input("Input total number of classes:"))
# Calculate the average of the two grades.
avg_grade = (grade1 + grade2) / 2
# Calculate the attendance rate as a percentage.
# 1. Subtract absences from total classes to get attended classes.
# 2. Divide attended classes by total classes.
# 3. Multiply by 100 to get a percentage.
attendance_rate = ((total_classes - absences) / total_classes) * 100
# Print the calculated average grade.
print("Average grade:", round(avg_grade, 2))
# Print the calculated attendance rate, followed by a '%' sign.
print("Attendance rate:", round(attendance_rate, 2), "%")
# Determine if the student is approved or failed based on grade and attendance.
# The student is approved if their average grade is 6 or higher AND their attendance rate is 80% or higher.
if avg_grade >= 6 and attendance_rate >= 80:
print("Approved")
# If both average grade is less than 6 AND attendance rate is less than 80%, they fail due to both.
elif avg_grade < 6 and attendance_rate < 80:
print("Failed due to low grade and low attendance.")
# If attendance is sufficient (80% or higher) but the grade is low (less than 6), they fail due to low grade.
elif attendance_rate >= 80: # This implies avg_grade < 6 because the first 'if' condition was not met.
print("Failed due to low grade.")
# If the grade is sufficient (6 or higher) but attendance is low (less than 80%), they fail due to low attendance.
# This 'else' covers the case where avg_grade >= 6 (because the second 'elif' was not met)
# and attendance_rate < 80 (because the first 'if' and third 'elif' were not met).
else: # This implies avg_grade >=6 and attendance_rate < 80
print("Failed due to low attendance.")
# Get input from the user for their weight and height.
# The `float()` function is used to convert the input (which is initially text) into a number with decimal points.
weight = float(input("Enter Weight (in kilograms):"))
height = float(input("Enter Height (in meters):"))
# Calculate BMI using the formula: weight / (height squared)
# BMI (Body Mass Index) is a measure of body fat based on height and weight.
bmi = weight / (height**2)
# Print the calculated BMI, rounded to two decimal places for readability.
print("Your Body Mass Index =", round(bmi, 2))
# Check the BMI value and print the corresponding category.
# These categories are based on common BMI classifications.
# If BMI is less than 18.5, the person is considered Underweight.
if bmi < 18.5:
print("You Are Under Weight")
# If BMI is between 18.5 (inclusive) and 24.9 (inclusive), the person is considered Normal Weight.
elif bmi >= 18.5 and bmi <= 24.9:
print("You Are Normal Weight")
# If BMI is between 24.9 (exclusive, so greater than 24.9) and 29.9 (exclusive, so less than 29.9),
# the person is considered Overweight.
elif bmi > 24.9 and bmi < 29.9:
print("You Are Over Weight")
# If BMI is 29.9 or greater, the person is considered to have Obesity.
# This 'else' covers all cases where BMI is not in the ranges above (i.e., >= 29.9).
else:
print("You Are Obesity")
number = input("Type a number:")
try:
number=float(number)
print("The number is ",number)
except:
print("Invalid Entry")
fname=input("Enter First Name:")
mname=input("Enter middle Name:")
lname=input("Enter Last Name:")
print ("Your Initials are " ,fname[0],'',mname[0],'',lname[0])
lot = "037-00901-00027"
print ('Country code:', lot[0:3])
print ('Product code:', lot[4:9])
print ('Batch code:' ,lot[-5:])
print ("This program calculates the average of two numbers")
print ('The numberss are 4 and 8') ; print ("The average is ", (4+8) / 2)
birth=input("Enter your birthday as {DD-MM-YYYY}:")
month=int(birth[3:5])
month=month-1
months=("January","Feburary","March","April","May","June","July","Agust","Septumber","Octuber","November","December")
print("You were born in",months[month])
# Python Advanced Data Structures: Sets, Tuples (In-depth), Dictionaries (In-depth)
import collections # For collections.namedtuple
# -----------------------------------
# 1. SETS
# -----------------------------------
# Sets are unordered collections of unique elements.
# This means an element cannot appear more than once in a set, and the order of elements is not guaranteed.
# Sets are mutable (you can add or remove elements).
# They are very useful for membership testing, removing duplicates from a sequence,
# and performing mathematical set operations like union, intersection, etc.
print("--- 1. Sets ---")
# --- a. Creating Sets ---
print("\n[Sets] Creating Sets:")
# Creating an empty set (must use set(), {} creates an empty dictionary)
empty_set = set()
print(f"Empty set: {empty_set}, type: {type(empty_set)}")
# Creating a set from a list (duplicates are automatically removed)
numbers_list = [1, 2, 2, 3, 4, 4, 4, 5]
numbers_set = set(numbers_list)
print(f"Set from list {numbers_list}: {numbers_set}") # Output: {1, 2, 3, 4, 5}
# Creating a set directly with elements
fruits_set = {"apple", "banana", "cherry", "apple"} # "apple" appears once
print(f"Set of fruits: {fruits_set}")
# --- b. Adding and Removing Elements ---
print("\n[Sets] Adding and Removing Elements:")
my_set = {1, 3}
print(f"Initial set: {my_set}")
# Add a single element
my_set.add(2) # Adds 2 to the set
print(f"After adding 2: {my_set}")
my_set.add(3) # Adding an existing element does nothing
print(f"After adding 3 again: {my_set}")
# Remove an element
# `remove()` will raise a KeyError if the element is not found.
my_set.remove(3)
print(f"After removing 3: {my_set}")
# my_set.remove(4) # This would cause a KeyError
# `discard()` also removes an element, but does not raise an error if it's not found.
my_set.discard(1)
print(f"After discarding 1: {my_set}")
my_set.discard(4) # No error, element 4 is not in the set
print(f"After discarding 4 (which wasn't there): {my_set}")
# Remove and return an arbitrary element using `pop()`.
# Raises KeyError if the set is empty.
my_set = {'a', 'b', 'c'}
print(f"Set before pop: {my_set}")
popped_element = my_set.pop()
print(f"Popped element: {popped_element}")
print(f"Set after pop: {my_set}")
# Clear all elements from a set
my_set.clear()
print(f"Set after clear: {my_set}")
# --- c. Common Set Operations ---
print("\n[Sets] Common 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}")
# Union: Elements present in either set_a or set_b (or both). Represented by | operator or .union() method.
union_set = set_a.union(set_b)
# union_set_operator = set_a | set_b # Alternative using operator
print(f"Union (A | B): {union_set}") # Output: {1, 2, 3, 4, 5, 6}
# Intersection: Elements present in both set_a and set_b. Represented by & operator or .intersection() method.
intersection_set = set_a.intersection(set_b)
# intersection_set_operator = set_a & set_b # Alternative
print(f"Intersection (A & B): {intersection_set}") # Output: {3, 4}
# Difference: Elements present in set_a but not in set_b. Represented by - operator or .difference() method.
difference_set_ab = set_a.difference(set_b) # A - B
# difference_set_ab_operator = set_a - set_b # Alternative
print(f"Difference (A - B): {difference_set_ab}") # Output: {1, 2}
difference_set_ba = set_b.difference(set_a) # B - A
print(f"Difference (B - A): {difference_set_ba}") # Output: {5, 6}
# Symmetric Difference: Elements present in either set_a or set_b, but not in both.
# Represented by ^ operator or .symmetric_difference() method.
symmetric_diff_set = set_a.symmetric_difference(set_b)
# symmetric_diff_set_operator = set_a ^ set_b # Alternative
print(f"Symmetric Difference (A ^ B): {symmetric_diff_set}") # Output: {1, 2, 5, 6}
# --- d. Set Use Cases ---
print("\n[Sets] Use Cases:")
# Membership testing (very efficient for sets)
my_data = {"apple", "banana", "cherry"}
print(f"Is 'apple' in my_data? {'apple' in my_data}") # True
print(f"Is 'grape' in my_data? {'grape' in my_data}") # False
# Removing duplicates from a list
my_list_with_duplicates = [10, 20, 30, 20, 10, 40, 50, 10]
unique_items_list = list(set(my_list_with_duplicates))
print(f"Original list: {my_list_with_duplicates}")
print(f"List after removing duplicates using set: {unique_items_list}")
# -----------------------------------
# 2. TUPLES (IN-DEPTH)
# -----------------------------------
# Tuples are ordered, immutable sequences. Immutable means once a tuple is created,
# its elements cannot be changed, added, or removed.
# They are often used to store collections of heterogeneous data (i.e., items of different types)
# or when you want to ensure that the data cannot be changed.
print("\n\n--- 2. Tuples (In-depth) ---")
# --- a. Revisiting Immutability ---
print("\n[Tuples] Immutability:")
my_tuple = (1, "hello", 3.14)
print(f"My tuple: {my_tuple}")
# my_tuple[0] = 2 # This would raise a TypeError: 'tuple' object does not support item assignment
# my_tuple.append("world") # This would raise an AttributeError: 'tuple' object has no attribute 'append'
# However, if a tuple contains mutable objects (like a list), the mutable object itself can be changed.
mutable_tuple = ([1, 2], "a_string")
print(f"Mutable tuple: {mutable_tuple}")
mutable_tuple[0].append(3) # The list inside the tuple is changed
print(f"Mutable tuple after modification: {mutable_tuple}") # Output: ([1, 2, 3], 'a_string')
# --- b. Packing and Unpacking ---
print("\n[Tuples] Packing and Unpacking:")
# Packing: When you assign a sequence of values to a single variable, Python packs them into a tuple.
packed_tuple = 10, 20, "packed" # No parentheses needed, but often used for clarity: (10, 20, "packed")
print(f"Packed tuple: {packed_tuple}, type: {type(packed_tuple)}")
# Unpacking: Assigning elements of a tuple to multiple variables.
# The number of variables must match the number of elements in the tuple.
a, b, c = packed_tuple
print(f"Unpacked: a={a}, b={b}, c={c}")
# Unpacking can be useful for swapping variables
x, y = 5, 10
print(f"Before swap: x={x}, y={y}")
x, y = y, x # y (10) is assigned to x, x (5) is assigned to y
print(f"After swap: x={x}, y={y}")
# Extended unpacking (Python 3) using *
numbers_tuple = (1, 2, 3, 4, 5)
first, second, *rest = numbers_tuple
print(f"Extended unpacking: first={first}, second={second}, rest={rest} (type: {type(rest)})")
first, *middle, last = numbers_tuple
print(f"Extended unpacking: first={first}, middle={middle}, last={last}")
# --- c. Named Tuples (collections.namedtuple) ---
# Named tuples provide a way to create tuple subclasses with named fields.
# This makes your code more readable as you can access elements by name instead of index.
print("\n[Tuples] Named Tuples:")
# Define a named tuple 'Point' with fields 'x' and 'y'
Point = collections.namedtuple('Point', ['x', 'y'])
# Point = collections.namedtuple('Point', 'x y') # Alternative string syntax for fields
# Create instances of the Point named tuple
p1 = Point(10, 20)
p2 = Point(x=30, y=40) # Can also use keyword arguments
print(f"Point p1: {p1}")
print(f"Point p2: {p2}")
# Access elements by name
print(f"p1.x = {p1.x}, p1.y = {p1.y}")
# Access elements by index (still possible, like regular tuples)
print(f"p2[0] = {p2[0]}, p2[1] = {p2[1]}")
# Named tuples are still immutable
# p1.x = 15 # This would raise an AttributeError
# You can convert a named tuple to a dictionary
print(f"p1 as dictionary: {p1._asdict()}")
# -----------------------------------
# 3. DICTIONARIES (IN-DEPTH)
# -----------------------------------
# Dictionaries are unordered (in Python versions before 3.7, ordered in 3.7+) collections of
# key-value pairs. Each key must be unique and immutable (e.g., string, number, or tuple).
# Values can be of any type and can be duplicated.
# Dictionaries are mutable.
print("\n\n--- 3. Dictionaries (In-depth) ---")
my_dict = {"name": "Alice", "age": 30, "city": "New York"}
print(f"Initial dictionary: {my_dict}")
# --- a. Iterating Through Dictionaries ---
print("\n[Dicts] Iterating:")
# Iterating through keys (this is the default iteration behavior)
print("Keys:")
for key in my_dict:
print(f" {key} (value: {my_dict[key]})")
# Iterating through values using .values()
print("\nValues:")
for value in my_dict.values():
print(f" {value}")
# Iterating through key-value pairs (items) using .items()
print("\nItems (key-value pairs):")
for key, value in my_dict.items():
print(f" Key: {key}, Value: {value}")
# --- b. Dictionary Comprehensions ---
# A concise way to create dictionaries.
print("\n[Dicts] Dictionary Comprehensions:")
# Example 1: Create a dictionary of squares
squares_dict = {x: x*x for x in range(1, 6)}
# Equivalent for loop:
# squares_dict_loop = {}
# for x in range(1, 6):
# squares_dict_loop[x] = x*x
print(f"Squares dictionary: {squares_dict}") # Output: {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# Example 2: From two lists
keys_list = ["a", "b", "c"]
values_list = [10, 20, 30]
dict_from_lists = {keys_list[i]: values_list[i] for i in range(len(keys_list))}
# A more Pythonic way for the above using zip:
# dict_from_lists_zip = {k: v for k, v in zip(keys_list, values_list)}
print(f"Dictionary from lists {keys_list} and {values_list}: {dict_from_lists}")
# Example 3: With a condition
original_prices = {"apple": 1.0, "banana": 0.5, "orange": 0.75, "grape": 2.0}
expensive_items = {item: price for item, price in original_prices.items() if price > 0.8}
print(f"Expensive items from {original_prices}: {expensive_items}")
# --- c. Safe Access with .get() and .setdefault() ---
print("\n[Dicts] Safe Access:")
student_grades = {"Alice": 85, "Bob": 92}
print(f"Grades: {student_grades}")
# Accessing a key that exists
print(f"Alice's grade: {student_grades['Alice']}")
# Accessing a key that does NOT exist using [] will raise a KeyError
# print(student_grades['Charlie']) # This would cause a KeyError
# Using .get(key, default_value) for safe access
# If the key exists, its value is returned.
# If the key does not exist, the default_value is returned (None if not specified).
charlie_grade = student_grades.get("Charlie")
print(f"Charlie's grade (using get()): {charlie_grade}") # Output: None
charlie_grade_default = student_grades.get("Charlie", "Not found") # Providing a default
print(f"Charlie's grade (using get() with default): {charlie_grade_default}") # Output: Not found
bob_grade = student_grades.get("Bob", "Not found")
print(f"Bob's grade (using get() with default): {bob_grade}") # Output: 92 (key exists)
# Using .setdefault(key, default_value)
# If the key exists, its value is returned.
# If the key does not exist, it is inserted into the dictionary with the default_value,
# and then default_value is returned.
print(f"\nUsing setdefault():")
print(f"Grades before setdefault for David: {student_grades}")
david_grade = student_grades.setdefault("David", 70) # David is not in dict, so he's added with grade 70
print(f"David's grade (using setdefault()): {david_grade}")
print(f"Grades after setdefault for David: {student_grades}")
alice_grade_setdefault = student_grades.setdefault("Alice", 90) # Alice exists, her grade is returned, dict not changed
print(f"Alice's grade (using setdefault()): {alice_grade_setdefault}")
print(f"Grades after setdefault for Alice: {student_grades}")
print("\n\n--- Advanced Data Structures Demonstration Complete ---")
# To run this file:
# 1. Save it as advanced_data_structures.py
# 2. Open a terminal or command prompt.
# 3. Navigate to the directory where you saved the file.
# 4. Run the script using the command: python advanced_data_structures.py
# The script will print its actions to the console, demonstrating each concept.
# Python Advanced Error Handling Techniques
# Error handling is crucial for writing robust and user-friendly programs.
# Python provides a flexible `try...except` mechanism to manage exceptions.
print("--- Advanced Error Handling ---")
# -------------------------------------------
# 1. Specific Exceptions
# -------------------------------------------
# It's good practice to catch specific exceptions rather than a generic `except Exception:` or `except:`.
# This allows you to handle different types of errors in different ways and prevents
# your program from accidentally catching exceptions you didn't intend to (like SystemExit or KeyboardInterrupt).
print("\n--- 1. Catching Specific Exceptions ---")
def divide_numbers_specific():
try:
numerator = int(input("[Specific] Enter numerator: "))
denominator = int(input("[Specific] Enter denominator: "))
result = numerator / denominator
print(f"[Specific] Result of division: {result}")
except ValueError:
# Handles errors if input cannot be converted to an integer (e.g., user types "abc")
print("[Specific] Error: Invalid input. Please enter numbers only.")
except ZeroDivisionError:
# Handles errors if the denominator is zero
print("[Specific] Error: Cannot divide by zero.")
# except Exception as e: # A more general fallback, but try to be specific first
# print(f"[Specific] An unexpected error occurred: {e}")
# divide_numbers_specific() # Uncomment to test this section
# -------------------------------------------
# 2. Multiple Exception Blocks
# -------------------------------------------
# You can have multiple `except` blocks to handle different types of exceptions
# that might occur within a single `try` block. Python will execute the first
# `except` block that matches the type of exception raised.
print("\n--- 2. Multiple Exception Blocks (same as above, just emphasizing the structure) ---")
# The `divide_numbers_specific()` function above already demonstrates multiple except blocks.
# Each `except` targets a different potential error: `ValueError` or `ZeroDivisionError`.
def open_and_process_file_multiple():
file_path = input("[Multiple] Enter file path to open (e.g., 'data.txt' or 'non_existent.txt'): ")
try:
with open(file_path, 'r') as file:
content = file.read()
# Let's imagine we want to convert the first line to an integer
first_line_value = int(content.splitlines()[0])
print(f"[Multiple] First line as integer: {first_line_value}")
print(f"[Multiple] File content:\n{content}")
except FileNotFoundError:
print(f"[Multiple] Error: The file '{file_path}' was not found.")
except ValueError:
print("[Multiple] Error: The first line of the file could not be converted to an integer.")
except IndexError:
print("[Multiple] Error: The file is empty or does not have enough lines.")
except Exception as e: # Catch-all for other unexpected errors
print(f"[Multiple] An unexpected error occurred: {e}")
# open_and_process_file_multiple() # Uncomment to test
# -------------------------------------------
# 3. The `else` Clause
# -------------------------------------------
# The `else` block is optional and, if present, is executed only if the `try` block
# completes without raising any exceptions.
# It's useful for code that should run only when the `try` part was successful.
print("\n--- 3. The `else` Clause ---")
def divide_numbers_with_else():
try:
numerator = int(input("[Else] Enter numerator: "))
denominator = int(input("[Else] Enter denominator: "))
result = numerator / denominator
except ValueError:
print("[Else] Error: Invalid input. Please enter numbers only.")
except ZeroDivisionError:
print("[Else] Error: Cannot divide by zero.")
else:
# This block runs only if no exceptions occurred in the try block.
print(f"[Else] Division successful! Result: {result}")
print("[Else] The 'else' block is a good place for code that depends on the try block succeeding.")
# divide_numbers_with_else() # Uncomment to test
# -------------------------------------------
# 4. The `finally` Clause
# -------------------------------------------
# The `finally` block is optional and, if present, is always executed,
# regardless of whether an exception occurred in the `try` block or not.
# It's typically used for cleanup actions, like closing files or releasing resources,
# ensuring these actions happen no matter what.
print("\n--- 4. The `finally` Clause ---")
def example_with_finally():
file = None # Initialize file variable
try:
print("\n[Finally] Attempting to open 'temp_file.txt' for writing.")
file = open("temp_file.txt", "w")
user_input = input("[Finally] Enter data to write (or type 'error' to cause one): ")
if user_input.lower() == 'error':
# Intentionally cause an error after the file is opened
result = 10 / 0
file.write(user_input)
print("[Finally] Data written to temp_file.txt successfully.")
except ZeroDivisionError:
print("[Finally] Error: Oops, a ZeroDivisionError occurred!")
except Exception as e:
print(f"[Finally] An unexpected error occurred: {e}")
finally:
# This block will always execute.
print("[Finally] The 'finally' block is executing now.")
if file: # Check if file was successfully opened
file.close()
print("[Finally] File 'temp_file.txt' has been closed.")
else:
print("[Finally] File was not opened, so no need to close.")
# You might also remove the temp file here if it's just for this example
# import os
# if os.path.exists("temp_file.txt"):
# os.remove("temp_file.txt")
# print("[Finally] temp_file.txt removed.")
# example_with_finally() # Uncomment to test
# -------------------------------------------
# 5. Raising Exceptions (`raise`)
# -------------------------------------------
# You can manually trigger (raise) exceptions using the `raise` keyword.
# This is useful when you detect an error condition in your code and want to
# signal that something has gone wrong, often based on custom logic.
print("\n--- 5. Raising Exceptions ---")
def validate_age(age):
try:
age_num = int(age)
if age_num < 0:
# Raise a ValueError if the age is negative, which is logically incorrect.
raise ValueError("Age cannot be negative.")
elif age_num < 18:
# Raise a custom message or a specific type of error for under-age.
raise Exception("User is underage for this service.") # Can be more specific
else:
print(f"[Raise] Age {age_num} is valid.")
return True
except ValueError as ve: # Catch the ValueError we might raise, or from int()
print(f"[Raise] Value Error: {ve}")
return False
except Exception as e: # Catch other exceptions we might raise
print(f"[Raise] General Error: {e}")
return False
# print("\n[Raise] Testing age validation:")
# validate_age("25")
# validate_age("-5")
# validate_age("abc")
# validate_age("15")
# -------------------------------------------
# 6. Custom Exceptions
# -------------------------------------------
# You can define your own custom exception classes by inheriting from the base `Exception` class
# (or a more specific built-in exception class).
# Custom exceptions make your error handling more specific and readable.
print("\n--- 6. Custom Exceptions ---")
# Define a custom exception class
class NegativeNumberError(Exception):
"""Custom exception raised when a non-negative number is expected but a negative one is given."""
def __init__(self, number, message="Negative numbers are not allowed here."):
self.number = number
self.message = message
# Call the base class constructor with the message
super().__init__(f"{message} (Received: {self.number})")
class ValueTooSmallError(Exception):
"""Custom exception for values that are too small."""
pass # Can be as simple as this if no extra attributes/methods are needed
def process_positive_number(num):
try:
if not isinstance(num, (int, float)):
raise TypeError("Input must be a number.")
if num < 0:
# Raise our custom exception
raise NegativeNumberError(num)
if num < 10:
raise ValueTooSmallError(f"The number {num} is too small, expected 10 or more.")
print(f"[CustomExc] Processing number: {num}. Square is {num*num}.")
except NegativeNumberError as nne:
# Handle our custom exception specifically
print(f"[CustomExc] NegativeNumberError Caught: {nne}")
# print(f"[CustomExc] The problematic number was: {nne.number}") # Access custom attribute
except ValueTooSmallError as vtse:
print(f"[CustomExc] ValueTooSmallError Caught: {vtse}")
except TypeError as te:
print(f"[CustomExc] TypeError Caught: {te}")
# print("\n[CustomExc] Testing custom exceptions:")
# process_positive_number(25)
# process_positive_number(-5)
# process_positive_number(5) # Will raise ValueTooSmallError
# process_positive_number("text") # Will raise TypeError
print("\n--- Advanced Error Handling Demonstration Complete ---")
print("Uncomment the function calls in the script to test each section interactively.")
# How to test:
# 1. Save this file as advanced_error_handling.py
# 2. Run `python advanced_error_handling.py` in your terminal.
# 3. Uncomment one function call at a time (e.g., `divide_numbers_specific()`)
# and re-run the script to see that specific error handling technique in action.
# Follow the prompts to provide input that might cause errors.
myage=20
userage=int(input("Enter the user age:"))
if(myage>userage):
print("Programmer is older then you")
elif(myage<userage):
print("You are older then Programmer")
else:
print("You and Programmer are of same age")
import math
r = float(input("Enter radius of the circle:"))
cir=2*math.pi*r
area=math.pi*(r**2)
area=round(area,2)
print('Area of a circle is :',area)
cir=round(cir,2)
print('Circumference of a circle :',cir)
num1=int(input("Enter first number:"))
num2=int(input("Enter second number:"))
if (num1>num2):
print(num1,"is greater then",num2)
elif(num1<num2):
print(num2,"is greater then",num1)
elif(num1==num2):
print(num1,"is equal to",num2)
else:
print("Wrong value")
colors=["red","yellow","purple","grey","pink","blue","black","white"]
import random
while True:
random_num=random.randint(0,len(colors)-1)
random_col=colors[random_num]
#print(random_col)
while True:
guess=input("Enter Color:").lower()
if (random_col==guess):
break
else:
print("Oops try again")
print("You Guessed it", random_col)
play_again=input("Play again 'Yes/No' :").lower()
if play_again=='no':
break
elif play_again=='yes':
continue
print("It was Fun, thanks")
myString="Some text"
type(myString)
mystring='Hi i am "MIKRAN"'
print (mystring)
len(mystring)
mystring[0]
mystring[len(mystring)-8]
data_valid=False
while data_valid==False:
grade1=int(input("Enter grade:"))
if grade1<0 or grade1>10:
print("Grade must be Between 0 and 10")
continue
else:
data_valid=True
data_valid=False
while data_valid == False:
grade2=int(input("Enter grade:"))
if grade2<0 or grade2>10:
print("Grade must be between 0 and 10")
continue
else:
data_valid=True
data_valid=False
while data_valid == False:
attendence=int(input("Enter Attendence:"))
if attendence<0 or attendence>50:
print("Attendence must be between 0 and 50")
continue
else:
data_valid=True
data_valid=False
while data_valid == False:
Absences=int(input("Enter Absences:"))
if Absences<0 or Absences>attendence:
print("Absences must be between 0 and ",attendence)
continue
else:
data_valid=True
avg=(grade1+grade2)/2
total=(attendence-Absences)/attendence
print("Your Average Grade:",round(avg,2))
print("Your Attendence:",total*100,"%")
if avg>=6.0 and total>=0.8:
print("Congrats! You have Passed")
elif avg<6.0 and total>=0.8:
print("Sorry! You failed due to low Grades")
elif avg>=6.0 and total<0.8:
print("Sorry! You failed due to low Attendence")
else:
print("Sorry! You failed due to low Attendence and Grades")
person={"name":"Mikran Sandhu","gender":"male","age":20,"address":"Gujranwala","phone":+923217112944}
key=input("What information you want of the person (name,age,gender,address,phone):").lower()
result=person.get(key,"That information is not avaliable")
print( result )
#json and request exercise
import requests
import json
import pprint
endGame=""
url="https://opentdb.com/api.php?amount=1&category=12&difficulty=easy&type=multiple"
while endGame != "quit":
x = requests.get(url)
if(x.status_code != 200):
endGame=input("Sorry! 404 _____ Press enter to try again or type 'quit' to Quit Game")
else:
data=json.loads(x.text)
pprint.pprint(data)
input("Press enter to get a new question")
people=[]
for x in range(0,8):
person=input("Enter a name:")
people.append(person)
import random
random_num=random.randint(0,7)
random_person=people[random_num]
print("lucky winner is:",random_person)
#exercise error handling
data_valid=False
while data_valid==False:
grade1= input("Enter grade:")
try:
grade1=float(grade1)
except:
print("Invalid input! Only numbers are accepted. Decimals should be seperated by a dot.")
continue
if grade1<0 or grade1>10:
print("Grade must be Between 0 and 10")
continue
else:
data_valid=True
data_valid=False
while data_valid == False:
grade2=input("Enter grade:")
try:
grade2=float(grade2)
except:
print("Invalid input! Only numbers are accepted. Decimals should be seperated by a dot.")
continue
if grade2<0 or grade2>10:
print("Grade must be between 0 and 10")
continue
else:
data_valid=True
data_valid=False
while data_valid == False:
attendence=input("Enter Attendence:")
try:
attendence=float(attendence)
except:
print("Invalid input! Only numbers are accepted. Decimals should be seperated by a dot.")
continue
if attendence<0 or attendence>50:
print("Attendence must be between 0 and 50")
continue
else:
data_valid=True
data_valid=False
while data_valid == False:
Absences=int(input("Enter Absences:"))
try:
Absences=float(Absences)
except:
print("Invalid input! Only numbers are accepted. Decimals should be seperated by a dot.")
continue
if Absences<0 or Absences>attendence:
print("Absences must be between 0 and ",attendence)
continue
else:
data_valid=True
avg=(grade1+grade2)/2
total=(attendence-Absences)/attendence
print("Your Average Grade:",round(avg,2))
print("Your Attendence:",total*100,"%")
if avg>=6.0 and total>=0.8:
print("Congrats! You have Passed")
elif avg<6.0 and total>=0.8:
print("Sorry! You failed due to low Grades")
elif avg>=6.0 and total<0.8:
print("Sorry! You failed due to low Attendence")
else:
print("Sorry! You failed due to low Attendence and Grades")
# Python File Operations: Text, CSV, and JSON
import os # To check for file existence and remove files
import csv # For working with CSV files
import json # For working with JSON files
# -----------------------------------
# 1. WORKING WITH TEXT FILES (.txt)
# -----------------------------------
print("--- 1. Text File Operations ---")
# --- a. Opening and Writing to a Text File ---
# The `open()` function is used to open a file.
# 'w' mode: Opens the file for writing.
# If the file exists, its content is overwritten.
# If the file does not exist, it's created.
# Using `with open(...) as ...` is recommended because it automatically closes the file
# even if errors occur.
file_path_txt = "sample.txt"
print(f"\n[Text] Writing to {file_path_txt}...")
try:
with open(file_path_txt, 'w') as file:
# The `write()` method writes a string to the file.
file.write("Hello, Python File I/O!\n")
file.write("This is the second line.\n")
# `writelines()` can write a list of strings. Each string should ideally end with '\n'.
lines_to_write = ["Third line here.\n", "And a fourth one.\n"]
file.writelines(lines_to_write)
print(f"[Text] Successfully wrote to {file_path_txt}")
except IOError as e:
print(f"[Text] Error writing to file: {e}")
# --- b. Reading from a Text File ---
# 'r' mode: Opens the file for reading (this is the default mode).
# Raises an error if the file does not exist.
print(f"\n[Text] Reading from {file_path_txt}...")
try:
with open(file_path_txt, 'r') as file:
# `read()`: Reads the entire content of the file into a single string.
print("\n[Text] Using file.read():")
content = file.read()
print(content)
# Re-open to demonstrate other read methods (cursor is at the end after read())
with open(file_path_txt, 'r') as file:
# `readline()`: Reads a single line from the file, including the newline character.
print("[Text] Using file.readline():")
line1 = file.readline()
print(f"Line 1: {line1.strip()}") # .strip() removes leading/trailing whitespace like '\n'
line2 = file.readline()
print(f"Line 2: {line2.strip()}")
with open(file_path_txt, 'r') as file:
# `readlines()`: Reads all lines from the file and returns them as a list of strings.
# Each string in the list includes the newline character.
print("\n[Text] Using file.readlines():")
lines = file.readlines()
for i, line in enumerate(lines):
print(f"Line {i+1}: {line.strip()}")
except FileNotFoundError:
print(f"[Text] Error: The file {file_path_txt} was not found.")
except IOError as e:
print(f"[Text] Error reading file: {e}")
# --- c. Appending to a Text File ---
# 'a' mode: Opens the file for appending.
# New data is written to the end of the file.
# If the file does not exist, it's created.
print(f"\n[Text] Appending to {file_path_txt}...")
try:
with open(file_path_txt, 'a') as file:
file.write("This line was appended.\n")
file.write("Another appended line.\n")
print(f"[Text] Successfully appended to {file_path_txt}")
# Verify by reading again
with open(file_path_txt, 'r') as file:
print("\n[Text] Content after appending:")
print(file.read())
except IOError as e:
print(f"[Text] Error appending to file: {e}")
# --- d. Reading and Writing ('r+' mode) ---
# 'r+' mode: Opens the file for both reading and writing.
# The file pointer is at the beginning. Overwrites existing content.
# Raises an error if the file does not exist.
print(f"\n[Text] Using 'r+' mode with {file_path_txt}...")
try:
with open(file_path_txt, 'r+') as file:
print(f"[Text] Initial content (r+): {file.readline().strip()}") # Read the first line
file.write("OVERWRITTEN FIRST LINE (r+)\n") # Overwrite from cursor position
# Note: Be careful with r+ as it can be tricky to manage cursor position.
# For complex operations, reading all, modifying, then writing all ('w') is often safer.
print(f"[Text] Successfully used 'r+' on {file_path_txt}")
with open(file_path_txt, 'r') as file:
print("\n[Text] Content after 'r+' modification:")
print(file.read())
except FileNotFoundError:
print(f"[Text] Error: The file {file_path_txt} was not found for 'r+' operation.")
except IOError as e:
print(f"[Text] Error with 'r+' operation: {e}")
# -----------------------------------
# 2. WORKING WITH CSV FILES (.csv)
# -----------------------------------
# CSV (Comma Separated Values) files are simple text files used to store tabular data.
print("\n\n--- 2. CSV File Operations ---")
file_path_csv = "sample.csv"
# --- a. Writing to a CSV File ---
# Data to write (list of lists, where each inner list is a row)
csv_data_to_write = [
["Name", "Age", "City"],
["Alice", 30, "New York"],
["Bob", 24, "Los Angeles"],
["Charlie", 28, "Chicago"]
]
print(f"\n[CSV] Writing to {file_path_csv}...")
try:
# `newline=''` is important to prevent blank rows in the CSV on some platforms.
with open(file_path_csv, 'w', newline='') as csvfile:
# `csv.writer` creates a writer object.
csv_writer = csv.writer(csvfile)
# `writerow()` writes a single row.
# `writerows()` writes multiple rows from a list of lists.
csv_writer.writerows(csv_data_to_write)
print(f"[CSV] Successfully wrote to {file_path_csv}")
except IOError as e:
print(f"[CSV] Error writing CSV file: {e}")
# --- b. Reading from a CSV File ---
print(f"\n[CSV] Reading from {file_path_csv}...")
try:
with open(file_path_csv, 'r', newline='') as csvfile:
# `csv.reader` creates a reader object.
csv_reader = csv.reader(csvfile)
# The reader object can be iterated over to get rows.
# Each row is returned as a list of strings.
print("[CSV] Contents:")
for row in csv_reader:
print(row) # Each 'row' is a list of strings
except FileNotFoundError:
print(f"[CSV] Error: The file {file_path_csv} was not found.")
except IOError as e:
print(f"[CSV] Error reading CSV file: {e}")
# --- c. Writing CSV data using csv.DictWriter (writing dictionaries) ---
csv_dict_data_to_write = [
{'Name': 'David', 'Age': 35, 'City': 'Boston'},
{'Name': 'Eve', 'Age': 22, 'City': 'Miami'}
]
# Define the fieldnames (column headers)
csv_fieldnames = ['Name', 'Age', 'City']
file_path_dict_csv = "sample_dict.csv"
print(f"\n[CSV] Writing dictionary data to {file_path_dict_csv}...")
try:
with open(file_path_dict_csv, 'w', newline='') as csvfile:
# `csv.DictWriter` needs the file object and a list of fieldnames.
dict_writer = csv.DictWriter(csvfile, fieldnames=csv_fieldnames)
# `writeheader()` writes the header row (fieldnames).
dict_writer.writeheader()
# `writerows()` writes all dictionaries in the list.
dict_writer.writerows(csv_dict_data_to_write)
print(f"[CSV] Successfully wrote dictionary data to {file_path_dict_csv}")
except IOError as e:
print(f"[CSV] Error writing DictWriter CSV: {e}")
# --- d. Reading CSV data using csv.DictReader (reading into dictionaries) ---
print(f"\n[CSV] Reading data as dictionaries from {file_path_dict_csv}...")
try:
with open(file_path_dict_csv, 'r', newline='') as csvfile:
# `csv.DictReader` treats each row as a dictionary,
# where keys are taken from the first (header) row.
dict_reader = csv.DictReader(csvfile)
print("[CSV] Contents (as dictionaries):")
for row_dict in dict_reader:
# Each 'row_dict' is an OrderedDict or dict (depending on Python version)
print(dict(row_dict)) # Convert to regular dict for cleaner printing
# print(f"Name: {row_dict['Name']}, Age: {row_dict['Age']}, City: {row_dict['City']}")
except FileNotFoundError:
print(f"[CSV] Error: The file {file_path_dict_csv} was not found.")
except IOError as e:
print(f"[CSV] Error reading DictReader CSV: {e}")
# -----------------------------------
# 3. WORKING WITH JSON FILES (.json)
# -----------------------------------
# JSON (JavaScript Object Notation) is a lightweight data-interchange format.
# It's easy for humans to read and write and easy for machines to parse and generate.
print("\n\n--- 3. JSON File Operations ---")
file_path_json = "sample.json"
# --- a. Writing to a JSON File (Serialization) ---
# Python dictionary to be stored as JSON
json_data_to_write = {
"name": "John Doe",
"age": 30,
"isStudent": False,
"courses": [
{"title": "History", "credits": 3},
{"title": "Math", "credits": 4}
],
"address": {
"street": "123 Main St",
"city": "Anytown"
}
}
print(f"\n[JSON] Writing to {file_path_json}...")
try:
with open(file_path_json, 'w') as jsonfile:
# `json.dump()` serializes a Python dictionary into a JSON formatted string
# and writes it to a file object.
# `indent=4` makes the JSON file human-readable with pretty printing.
json.dump(json_data_to_write, jsonfile, indent=4)
print(f"[JSON] Successfully wrote to {file_path_json}")
except IOError as e:
print(f"[JSON] Error writing JSON file: {e}")
# --- b. Reading from a JSON File (Deserialization) ---
print(f"\n[JSON] Reading from {file_path_json}...")
try:
with open(file_path_json, 'r') as jsonfile:
# `json.load()` deserializes a JSON formatted string from a file object
# into a Python dictionary.
loaded_data = json.load(jsonfile)
print("[JSON] Contents (as Python dictionary):")
print(loaded_data)
print(f"[JSON] Name from loaded data: {loaded_data['name']}")
print(f"[JSON] First course title: {loaded_data['courses'][0]['title']}")
except FileNotFoundError:
print(f"[JSON] Error: The file {file_path_json} was not found.")
except json.JSONDecodeError as e:
print(f"[JSON] Error decoding JSON: {e}")
except IOError as e:
print(f"[JSON] Error reading JSON file: {e}")
# --- c. `dumps` and `loads` (string operations) ---
# `json.dumps()`: Serializes a Python object to a JSON formatted string (not to a file).
# `json.loads()`: Deserializes a JSON formatted string to a Python object.
print("\n[JSON] Using json.dumps() and json.loads()...")
python_dict = {"key": "value", "number": 42}
json_string = json.dumps(python_dict, indent=2) # Serialize to string
print(f"[JSON] Python dict serialized to JSON string:\n{json_string}")
reloaded_python_dict = json.loads(json_string) # Deserialize from string
print(f"[JSON] JSON string deserialized back to Python dict:\n{reloaded_python_dict}")
print(f"[JSON] Value from reloaded dict: {reloaded_python_dict['key']}")
# -----------------------------------
# 4. CLEANUP (Optional)
# -----------------------------------
# This section removes the files created by the script.
# You might want to comment this out if you want to inspect the files after running.
print("\n\n--- 4. Cleaning Up Sample Files ---")
files_to_remove = [file_path_txt, file_path_csv, file_path_dict_csv, file_path_json]
for f_path in files_to_remove:
try:
if os.path.exists(f_path):
os.remove(f_path)
print(f"[Cleanup] Successfully removed {f_path}")
else:
print(f"[Cleanup] File not found, no need to remove: {f_path}")
except OSError as e:
print(f"[Cleanup] Error removing file {f_path}: {e}")
print("\n--- File Operations Demonstration Complete ---")
# To run this file:
# 1. Save it as file_operations.py
# 2. Open a terminal or command prompt.
# 3. Navigate to the directory where you saved the file.
# 4. Run the script using the command: python file_operations.py
# The script will print its actions to the console and create/delete sample files.
print ('My first python program')
print (2+3)
blog_post=["python","","cpp","","java"]
for post in blog_post:
if post=="":
continue
else:
print(post)
print("________________________")
mystring="this is a string"
for char in mystring:
print(char)
print("________________________")
for x in range(0,10):
print(x)
print("________________________")
person={"Name":"Mikran","Age":10,"Gender":"male"}
for key in person:
print(key, ":" ,person[key])
print("________________________")
blog_post={"one":["python","","cpp","","java"],"two":["python","","cpp","","java"]}
for cat in blog_post:
print("Post no:",cat)
for post in blog_post[cat]:
if post =="":
continue
else:
print(post)
# Functions are reusable blocks of code that perform a specific task.
# This is a simple function that greets a person.
# 'person' is a parameter - it's a placeholder for the value that will be passed to the function when it's called.
def say_hello_simple(person):
# This function now returns a greeting string.
# It uses an f-string (formatted string literal) to include the 'person' variable directly in the string.
return f"Hello {person}, How are you"
# Calling the say_hello_simple function and printing its returned value.
# An argument is the actual value passed to a function's parameter.
returned_greeting_simple = say_hello_simple("mms")
print(f"Output of say_hello_simple('mms'): {returned_greeting_simple}")
# This function converts a temperature from Fahrenheit to Celsius.
# 'fahr' is the parameter representing the temperature in Fahrenheit.
def fahrtocelsius(fahr):
# This is the formula to convert Fahrenheit to Celsius.
# 1. Subtract 32 from the Fahrenheit temperature.
# 2. Multiply the result by 5.
# 3. Divide that result by 9.
celsius = (5 * (fahr - 32)) / 9
# This line returns the calculated Celsius temperature.
# The 'return' statement sends a value back to where the function was called.
return celsius
# Calling the fahrtocelsius function with 100 as the argument.
# The result is rounded to 2 decimal places for better readability.
celsius_temp = fahrtocelsius(100)
print(f"Celsius output for fahrtocelsius(100): {round(celsius_temp, 2)}")
# This is a more advanced greeting function with a default parameter value.
# 'person1' is a required parameter.
# 'person2' is an optional parameter with a default value of "mafia".
# If no value is provided for 'person2' when the function is called, "mafia" will be used.
def say_hello_adv(person1, person2="mafia"):
# This function now returns a greeting string including both person1 and person2.
return f"Hello {person1}, How are you? And hello to {person2}!"
# Calling the say_hello_adv function with two arguments and printing its returned value.
returned_greeting_adv1 = say_hello_adv("mms", "ucp")
print(f"Output of say_hello_adv('mms', 'ucp'): {returned_greeting_adv1}")
# Calling the say_hello_adv function with only one argument and printing its returned value.
returned_greeting_adv2 = say_hello_adv("friend")
print(f"Output of say_hello_adv('friend'): {returned_greeting_adv2}")
import random
number=random.randint(0,10)
guess=int(input("'I am thinking about a number between 1-10' Guess:"))
while True:
if guess==number:
print(number,"it is")
break
else:
print("Try again")
guess=int(input("'I am thinking about a number between 1-10' Guess:"))
grade1=float(input("Input grade:"))
grade2=float(input("Input grade:"))
absences=int(input("Input absents:"))
total_classes = int(input("Total classes:"))
avg_grade=(grade1+grade2)/2
attendence=((total_classes-absences)/total_classes)*100
print("Average grade:",avg_grade)
print("Attendence rate:",attendence ,"%"
)
if(avg_grade>=6):
if(attendence>=80):
print("Approved")
else:
print("Fail because of low attendence")
elif(attendence>=80):
print("Fail because of low grade")
else:
print("Fail because of low attendence and low grade")
a=input ("Enter a number=")
b=input ("Enter a number=")
summ=int(a)+int(b)
avg=summ/2
print ('Average =' , avg)
import requests
import json
import pprint
r=requests.get("https://opentdb.com/api.php?amount=1&category=12&difficulty=easy&type=multiple")
r.status_code
#json to dictionary
question=json.loads(r.text)
pprint.pprint(question)
question["results"][0]["category"]
#dictionary to json
person={"name":"ali","age":"20"}
person_json=json.dumps(person)
person_json
km = input("Input Kilometer=")
mile= float(km) / 1.609344
print ('Miles=',mile)
print ('Miles=',round(mile,3) ,'miles')
# Python Lambda Functions (Anonymous Functions)
# A lambda function is a small, anonymous, inline function defined using the `lambda` keyword.
# They are also known as "anonymous functions" because they don't have a formal name
# defined with `def` (unless you assign them to a variable, which is common).
# Syntax:
# lambda arguments: expression
# - `lambda`: The keyword that indicates you are defining a lambda function.
# - `arguments`: One or more arguments, separated by commas (just like regular function arguments).
# - `expression`: A single expression that is evaluated and returned.
# Lambda functions cannot contain multiple expressions or complex statements. They are limited
# to a single expression.
print("--- Lambda Functions ---")
# -------------------------------------------
# 1. Basic Lambda Function Syntax
# -------------------------------------------
print("\n--- 1. Basic Lambda Function Syntax ---")
# Example: A lambda function that adds two numbers.
add = lambda x, y: x + y
# - `lambda`: Keyword
# - `x, y`: Arguments
# - `x + y`: Expression (this value will be returned)
# Calling the lambda function (it's assigned to the variable 'add')
result = add(5, 3)
print(f"Result of add(5, 3): {result}") # Output: 8
# You can use lambda functions immediately without assigning them to a variable,
# though this is less common for direct calls and more for passing as arguments.
immediate_result = (lambda a, b: a * b)(4, 5)
print(f"Result of (lambda a, b: a * b)(4, 5): {immediate_result}") # Output: 20
# Comparison with a regular function defined using `def`:
def add_def(x, y):
return x + y
result_def = add_def(5, 3)
print(f"Result of add_def(5, 3) (using def): {result_def}")
# Lambda functions are more concise for simple, single-expression functions.
# -------------------------------------------
# 2. Use Cases for Lambda Functions
# -------------------------------------------
# Lambda functions are most useful when you need a small, throwaway function for a short period,
# often as an argument to higher-order functions (functions that take other functions as arguments).
print("\n--- 2. Use Cases for Lambda Functions ---")
# --- a. With `sorted()` ---
# The `sorted()` function can take a `key` argument, which is a function that
# returns a value to be used for sorting. Lambdas are perfect for simple keys.
print("\n[Lambda] Using with sorted():")
points = [(1, 5), (3, 2), (5, 8), (2, 0)]
print(f"Original points: {points}")
# Sort points based on the second element (y-coordinate) of each tuple
# Using a lambda function as the key:
# For each item `p` in `points`, `lambda p: p[1]` returns `p[1]` (the y-coordinate).
sorted_by_y = sorted(points, key=lambda p: p[1])
print(f"Points sorted by y-coordinate (using lambda): {sorted_by_y}")
# For comparison, using a regular function:
def get_y_coordinate(point):
return point[1]
sorted_by_y_def = sorted(points, key=get_y_coordinate)
print(f"Points sorted by y-coordinate (using def): {sorted_by_y_def}")
# The lambda version is more compact for this simple key.
# Sort a list of dictionaries by a specific key's value
students = [
{'name': 'Alice', 'grade': 85},
{'name': 'Bob', 'grade': 92},
{'name': 'Charlie', 'grade': 78}
]
print(f"\nOriginal students: {students}")
sorted_students_by_grade = sorted(students, key=lambda student: student['grade'])
print(f"Students sorted by grade (using lambda): {sorted_students_by_grade}")
# --- b. With `map()` ---
# The `map()` function applies a given function to each item of an iterable (e.g., list)
# and returns a map object (which can be converted to a list).
print("\n[Lambda] Using with map():")
numbers = [1, 2, 3, 4, 5]
print(f"Original numbers: {numbers}")
# Goal: Create a new list where each number is squared.
# Using lambda with map:
# `lambda x: x * x` is applied to each element `x` in `numbers`.
squared_numbers_map = map(lambda x: x * x, numbers)
squared_numbers_list = list(squared_numbers_map) # Convert map object to list
print(f"Squared numbers (using lambda with map): {squared_numbers_list}")
# For comparison, using a list comprehension (often preferred over map for this):
squared_numbers_comp = [x * x for x in numbers]
print(f"Squared numbers (using list comprehension): {squared_numbers_comp}")
# For comparison, using a regular function with map:
def square(x):
return x * x
squared_numbers_map_def = map(square, numbers)
print(f"Squared numbers (using def with map): {list(squared_numbers_map_def)}")
# Lambda is concise for simple transformations with map.
# --- c. With `filter()` ---
# The `filter()` function constructs an iterator from elements of an iterable
# for which a function returns true.
print("\n[Lambda] Using with filter():")
numbers_for_filter = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(f"Original numbers for filter: {numbers_for_filter}")
# Goal: Create a list of only the even numbers.
# Using lambda with filter:
# `lambda x: x % 2 == 0` returns True if x is even, False otherwise.
# filter() will include only those elements for which the lambda returns True.
even_numbers_filter = filter(lambda x: x % 2 == 0, numbers_for_filter)
even_numbers_list = list(even_numbers_filter) # Convert filter object to list
print(f"Even numbers (using lambda with filter): {even_numbers_list}")
# For comparison, using a list comprehension (often preferred over filter for this):
even_numbers_comp = [x for x in numbers_for_filter if x % 2 == 0]
print(f"Even numbers (using list comprehension): {even_numbers_comp}")
# For comparison, using a regular function with filter:
def is_even(x):
return x % 2 == 0
even_numbers_filter_def = filter(is_even, numbers_for_filter)
print(f"Even numbers (using def with filter): {list(even_numbers_filter_def)}")
# Lambda is concise for simple filtering conditions.
# -------------------------------------------
# 3. When to Use Lambda Functions
# -------------------------------------------
# - **Short, simple operations:** When the function logic is very simple and can be expressed in a single line.
# - **As arguments to higher-order functions:** This is the most common and idiomatic use (e.g., `map`, `filter`, `sorted`, UI event handlers).
# - **Readability for simple cases:** For simple tasks, a lambda can be more readable than defining a full function, as the logic is right where it's used.
# When NOT to use Lambda Functions:
# - **Complex logic:** If the function requires multiple lines of code, complex logic, or many statements, use a regular `def` function.
# - **When you need docstrings:** Lambda functions cannot have docstrings.
# - **When you need type hints for arguments/return value in a reusable way:** While you can assign a lambda to a variable and type hint that variable, `def` functions offer more standard and readable type hinting.
# - **If it makes the code harder to read:** If a lambda becomes too convoluted, a named `def` function is often clearer.
print("\n--- Lambda Functions Demonstration Complete ---")
# To run this file:
# 1. Save it as lambda_functions.py
# 2. Open a terminal or command prompt.
# 3. Navigate to the directory where you saved the file.
# 4. Run the script using the command: python lambda_functions.py
# The script will print the results of various lambda function applications.
people=['Mikran','Imran','Mawaan']
print(people)
new=input("Enter a name you want to add in the list:")
people.append(new)
print(people)
rem=input("Enter a name you want to remove in the list:")
people.remove(rem)
print(people)
exn=input("Enter a name you want to exchange in the list:")
pos=int(input("Enter a position you want to exchange in the list:"))
people.insert(pos,exn)
print(people)
people.pop()
print(people)
# Python List Comprehensions
# List comprehensions provide a concise and readable way to create lists.
# They are often more compact and faster than using traditional `for` loops
# and `append()` calls to build a list.
# The basic syntax is:
# new_list = [expression for item in iterable if condition]
# - expression: The expression to compute for each item (e.g., item * 2).
# - item: The variable representing each element from the iterable.
# - iterable: A sequence or collection to iterate over (e.g., a list, range, tuple).
# - condition (optional): A filter that includes the item in the new list only if the condition is True.
print("--- List Comprehensions ---")
# -------------------------------------------
# 1. Basic List Comprehension (from a range)
# -------------------------------------------
print("\n--- 1. Basic List Comprehension (from a range) ---")
# Goal: Create a list of squares from 0 to 9.
# Using a traditional for loop:
squares_loop = []
for x in range(10): # range(10) produces numbers 0, 1, ..., 9
squares_loop.append(x * x)
print(f"Squares (using for loop): {squares_loop}")
# Using a list comprehension:
# expression: x * x
# item: x
# iterable: range(10)
squares_comp = [x * x for x in range(10)]
print(f"Squares (using comprehension): {squares_comp}")
# Notice how the list comprehension is more compact.
# -------------------------------------------------
# 2. List Comprehension with Transformation
# -------------------------------------------------
print("\n--- 2. List Comprehension with Transformation ---")
# Goal: Create a list of uppercase words from a list of lowercase words.
words = ["hello", "world", "python", "is", "fun"]
print(f"Original words: {words}")
# Using a traditional for loop:
uppercase_words_loop = []
for word in words:
uppercase_words_loop.append(word.upper()) # .upper() converts a string to uppercase
print(f"Uppercase (using for loop): {uppercase_words_loop}")
# Using a list comprehension:
# expression: word.upper()
# item: word
# iterable: words
uppercase_words_comp = [word.upper() for word in words]
print(f"Uppercase (using comprehension): {uppercase_words_comp}")
# -------------------------------------------------
# 3. List Comprehension with a Conditional Clause (if)
# -------------------------------------------------
print("\n--- 3. List Comprehension with a Conditional Clause (if) ---")
# Goal: Create a list of even numbers from 0 to 19.
numbers = range(20) # Numbers from 0 to 19
print(f"Original numbers: {list(numbers)}") # Convert range to list for printing
# Using a traditional for loop:
even_numbers_loop = []
for num in numbers:
if num % 2 == 0: # The condition: num is even if num modulo 2 is 0
even_numbers_loop.append(num)
print(f"Even numbers (using for loop): {even_numbers_loop}")
# Using a list comprehension with an if condition:
# expression: num
# item: num
# iterable: numbers
# condition: num % 2 == 0
even_numbers_comp = [num for num in numbers if num % 2 == 0]
print(f"Even numbers (using comprehension): {even_numbers_comp}")
# Goal: Get words longer than 3 characters from the 'words' list.
print(f"\nOriginal words: {words}")
long_words_comp = [word for word in words if len(word) > 3]
print(f"Long words (using comprehension): {long_words_comp}")
# -------------------------------------------------
# 4. List Comprehension with 'if-else' (Conditional Expression)
# -------------------------------------------------
print("\n--- 4. List Comprehension with 'if-else' ---")
# Note: The syntax for if-else within a list comprehension is different from the filtering 'if'.
# It's `expression_if_true if condition else expression_if_false` and comes *before* the `for` loop.
# Goal: Create a list where numbers are labeled 'even' or 'odd'.
numbers_to_label = range(1, 6) # 1, 2, 3, 4, 5
print(f"Numbers to label: {list(numbers_to_label)}")
# Using a traditional for loop:
labels_loop = []
for num in numbers_to_label:
if num % 2 == 0:
labels_loop.append(f"{num} is even")
else:
labels_loop.append(f"{num} is odd")
print(f"Labels (using for loop): {labels_loop}")
# Using a list comprehension with an if-else expression:
# expression: f"{num} is even" if num % 2 == 0 else f"{num} is odd"
# item: num
# iterable: numbers_to_label
labels_comp = [f"{num} is even" if num % 2 == 0 else f"{num} is odd" for num in numbers_to_label]
print(f"Labels (using comprehension): {labels_comp}")
# -------------------------------------------------
# 5. Nested List Comprehensions (Use with caution, can be hard to read)
# -------------------------------------------------
print("\n--- 5. Nested List Comprehensions ---")
# Goal: Create a flattened list from a list of lists (a matrix).
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
print(f"Original matrix: {matrix}")
# Using traditional nested for loops:
flattened_loop = []
for row in matrix:
for item in row:
flattened_loop.append(item)
print(f"Flattened (using for loops): {flattened_loop}")
# Using a nested list comprehension:
# The 'for' clauses are in the same order as in the traditional loop.
# expression: item
# outer loop: for row in matrix
# inner loop: for item in row
flattened_comp = [item for row in matrix for item in row]
print(f"Flattened (using comprehension): {flattened_comp}")
# Another example: Create pairs from two lists
list1 = ['A', 'B']
list2 = [1, 2]
print(f"\nList 1: {list1}, List 2: {list2}")
pairs_comp = [(l1, l2) for l1 in list1 for l2 in list2] # (l1, l2) creates a tuple for each pair
print(f"Pairs (using comprehension): {pairs_comp}")
# Output: [('A', 1), ('A', 2), ('B', 1), ('B', 2)]
# While powerful, deeply nested comprehensions can become difficult to understand.
# If it's too complex, a traditional for loop might be more readable.
# -------------------------------------------------
# Benefits of List Comprehensions:
# -------------------------------------------------
# 1. Conciseness and Readability: Often more compact and easier to read than equivalent loops,
# once you are familiar with the syntax.
# 2. Performance: Can be faster than using `append()` in a loop, as they are optimized in CPython.
# (Though for very complex expressions, this might not always hold true).
# 3. Expressiveness: They are a very Pythonic way to create lists.
print("\n--- List Comprehensions Demonstration Complete ---")
# To run this file:
# 1. Save it as list_comprehensions.py
# 2. Open a terminal or command prompt.
# 3. Navigate to the directory where you saved the file.
# 4. Run the script using the command: python list_comprehensions.py
# The script will print the lists created using both traditional loops and comprehensions.
import matplotlib.pyplot as plt
x=[1,2,3,4]
y=[5,6,7,8]
plt.plot(x,y)
plt.show()
legend=['january','february','march','april']
plt.xticks(x,legend)
plt.show()
plt.bar(x,y)
plt.show()
plt.title("Montly Sales")
plt.ylabel("this is a chart")
plt.show()
plt.bar(x,y)
plt.show()
# Object-Oriented Programming (OOP) Concepts in Python
# OOP is a programming paradigm based on the concept of "objects",
# which can contain data in the form of fields (often known as attributes or properties)
# and code in the form of procedures (often known as methods).
# -----------------------------------
# 1. CLASSES
# -----------------------------------
# A class is a blueprint for creating objects. It defines a set of attributes and methods
# that the created objects will have.
print("--- 1. Classes and Objects ---")
class Dog:
# This is a class attribute. It's shared by all instances (objects) of the class.
species = "Canis familiaris"
# This is the constructor method, also known as the initializer.
# It's automatically called when you create a new object (instance) of the class.
# 'self' refers to the instance being created.
# 'name' and 'age' are instance attributes, specific to each object.
def __init__(self, name, age):
self.name = name # Attribute specific to each Dog instance
self.age = age # Attribute specific to each Dog instance
self._secret_trick = "Roll over" # Example of a "non-public" attribute convention
self.__very_secret_mood = "Always happy" # Example of name mangling for "pseudo-private"
# This is an instance method. It operates on an instance of the class ('self').
def description(self):
# f-strings (formatted string literals) are a convenient way to embed expressions inside string literals.
return f"{self.name} is {self.age} years old."
# Another instance method
def speak(self, sound):
return f"{self.name} says {sound}!"
# Method to demonstrate accessing "private" attributes (for illustration)
def reveal_secret_trick(self):
return f"{self.name}'s secret trick is to {self._secret_trick}."
def reveal_mood(self):
# Accessing name-mangled attribute (Python renames it to _ClassName__attributeName)
return f"{self.name}'s mood: {self._Dog__very_secret_mood}"
# -----------------------------------
# 2. OBJECTS (Instances)
# -----------------------------------
# An object is an instance of a class. When a class is defined, no memory is allocated
# until an object of that class is created.
# Creating (instantiating) objects of the Dog class
dog1 = Dog("Buddy", 3) # Calls the __init__ method with name="Buddy", age=3
dog2 = Dog("Lucy", 5) # Calls the __init__ method with name="Lucy", age=5
# Accessing instance attributes
print(f"{dog1.name} is an instance of Dog.")
print(f"{dog2.name} is also an instance of Dog.")
# Accessing class attributes
# Can be accessed via the class itself or an instance
print(f"All dogs belong to the species: {Dog.species}")
print(f"{dog1.name} is a {dog1.species}.")
# Calling instance methods
print(dog1.description()) # Output: Buddy is 3 years old.
print(dog2.speak("Woof")) # Output: Lucy says Woof!
# -----------------------------------
# 3. INHERITANCE
# -----------------------------------
# Inheritance allows a new class (child/derived class) to inherit attributes and methods
# from an existing class (parent/base class). This promotes code reuse.
print("\n--- 3. Inheritance ---")
# Parent class (already defined as Dog)
# Child class inheriting from Dog
class GoldenRetriever(Dog):
# The child class can have its own __init__ method.
def __init__(self, name, age, favorite_toy):
# 'super()' calls the __init__ method of the parent class (Dog).
# This ensures that the parent's initialization logic (like setting name and age) is executed.
super().__init__(name, age)
self.favorite_toy = favorite_toy # Attribute specific to GoldenRetriever
# Child class can have its own methods
def fetch(self, item):
return f"{self.name} fetches the {item}. Their favorite toy is {self.favorite_toy}."
# Child class can also override methods from the parent class
def speak(self, sound="Bark"): # Overriding the speak method
return f"{self.name} (a Golden Retriever) enthusiastically says {sound}!"
# Creating an instance of the child class
golden = GoldenRetriever("Charlie", 2, "tennis ball")
# Accessing attributes and methods from both parent and child class
print(golden.description()) # Inherited from Dog: Charlie is 2 years old.
print(golden.speak()) # Overridden in GoldenRetriever: Charlie (a Golden Retriever) enthusiastically says Bark!
print(golden.speak("Grrr")) # Overridden in GoldenRetriever: Charlie (a Golden Retriever) enthusiastically says Grrr!
print(golden.fetch("stick")) # Defined in GoldenRetriever: Charlie fetches the stick. Their favorite toy is tennis ball.
print(f"{golden.name} is a {golden.species}") # Accessing class attribute inherited from Dog
# -----------------------------------
# 4. ENCAPSULATION
# -----------------------------------
# Encapsulation is the bundling of data (attributes) and methods that operate on the data
# into a single unit (a class). It also restricts direct access to some of an object's components.
# Python doesn't have strict private attributes like Java or C++, but uses conventions:
# - _non_public: Treated as a hint that it's for internal use.
# - __pseudo_private: Name mangling is applied (e.g., __mood becomes _Dog__mood).
# This makes it harder to access accidentally from outside but not truly private.
print("\n--- 4. Encapsulation ---")
# dog1 is an instance of Dog class created earlier
print(f"Dog's name: {dog1.name}") # Public attribute, directly accessible
# Accessing "non-public" attribute (by convention, should be avoided directly from outside)
# print(f"Dog's secret trick (direct access): {dog1._secret_trick}") # Possible, but not recommended
print(dog1.reveal_secret_trick()) # Accessing via a public method is preferred
# Accessing "pseudo-private" attribute (name mangled)
# print(dog1.__very_secret_mood) # This would cause an AttributeError
# Accessing it via its mangled name (demonstrates it's not truly private)
# print(f"Dog's mood (mangled name access): {dog1._Dog__very_secret_mood}") # Possible, but not recommended
print(dog1.reveal_mood()) # Accessing via a public method is preferred
# The idea is to protect attributes from accidental modification and to manage access through methods.
# -----------------------------------
# 5. POLYMORPHISM
# -----------------------------------
# Polymorphism means "many forms". In OOP, it refers to the ability of different classes
# to be treated as objects of a common superclass.
# A common use is "duck typing": "If it walks like a duck and quacks like a duck, then it must be a duck."
# This means Python cares more about whether an object has a certain method or property,
# rather than its specific type.
# More commonly, polymorphism allows different classes to have methods with the same name,
# and these methods can behave differently for each class.
print("\n--- 5. Polymorphism ---")
class Cat(Dog): # Let's make Cat inherit from Dog for this example, though not biologically accurate
def __init__(self, name, age, color):
super().__init__(name, age) # Call Dog's init
self.color = color
# Cat has its own 'speak' method
def speak(self, sound="Meow"): # Overriding the speak method
return f"{self.name} (a cat) purrs: {sound}"
class Parrot: # Parrot does not inherit from Dog
def __init__(self, name, can_talk=True):
self.name = name
self.can_talk = can_talk
# Parrot also has a 'speak' method
def speak(self, phrase="Squawk"):
if self.can_talk:
return f"{self.name} (a parrot) repeats: '{phrase}'"
else:
return f"{self.name} (a parrot) just squawks."
# Create instances of Dog, Cat, and Parrot
dog_poly = Dog("Rex", 4)
cat_poly = Cat("Whiskers", 3, "grey")
parrot_poly = Parrot("Polly")
silent_parrot = Parrot("Silent Bob", can_talk=False)
# Create a list of different animal objects
animals = [dog_poly, cat_poly, parrot_poly, silent_parrot]
# Iterate through the list and call the 'speak' method on each object.
# Even though each object is of a different class (or configured differently),
# they all respond to the 'speak()' call in their own way.
print("\nDemonstrating Polymorphism (common method name):")
for animal in animals:
# Python doesn't strictly check if 'animal' is of a specific type that 'must' have .speak().
# It just tries to call .speak(). If the method exists, it works. This is duck typing.
if hasattr(animal, 'speak'): # Good practice to check if method exists
print(animal.speak())
else:
print(f"{animal.name} can't speak.")
# Another example: a function that uses the .speak() method
def animal_communication(animal_object):
# This function doesn't care what type of animal_object it is,
# as long as it has a 'speak' method.
print(f"Communicating with {animal_object.name}: {animal_object.speak('Hello!')}")
print("\nDemonstrating Polymorphism (duck typing with a function):")
animal_communication(dog_poly)
animal_communication(cat_poly)
animal_communication(parrot_poly)
print("\n--- OOP Concepts Demonstration Complete ---")
# To run this file, save it as oop_concepts.py and run 'python oop_concepts.py' in your terminal.
# You will see the output of the print statements demonstrating each concept.
import matplotlib.pyplot as plt
import numpy as np
plt.style.use('_mpl-gallery')
# make data
x = np.linspace(0, 10, 100)
y = 4 + 1 * np.sin(2 * x)
x2 = np.linspace(0, 10, 25)
y2 = 4 + 1 * np.sin(2 * x2)
# plot
fig, ax = plt.subplots()
ax.plot(x2, y2 + 2.5, 'x', markeredgewidth=2)
ax.plot(x, y, linewidth=2.0)
ax.plot(x2, y2 - 2.5, 'o-', linewidth=2)
ax.set(xlim=(0, 8), xticks=np.arange(1, 8),
ylim=(0, 8), yticks=np.arange(1, 8))
plt.show()
#import requests
#r=requests.get("https://www.google.com")
#print(r.status_code)
#print(r.headers)
#r.text
#r.headers["Date"]
# Initialize an empty list for names
people = []
# Collect 8 names from the user
for x in range(0, 8):
person = input("Enter a name: ")
people.append(person)
# Input the name to search for
getnam = input("Enter the name you want to search: ")
# Search for the name in the list
if getnam in people:
print("Name found")
else:
print("Name not found")
import time as t
import sys
print(sys.path)
import matplotlib.pyplot as plt
# Setting the word for the typing test
word = "pakistan"
# Validating the difficulty level
while True:
n = int(input("Enter difficulty level (1-10): "))
if n < 1 or n > 10:
print("Wrong level!")
continue
else:
break
num = n # To preserve the original difficulty level
print(f"Write the word '{word}' {n} times.")
times = [] # To store time taken for each attempt
mistake = 0 # To count mistakes
# Typing test loop
while n:
start = t.time() # Start the timer
test = input("Enter: ")
end = t.time() # End the timer
time_taken = end - start
times.append(time_taken)
# Decrement the remaining attempts
n -= 1
# Count mistakes
if test != word:
mistake += 1
# Generating attempt numbers for plotting
y = list(range(1, num + 1)) # Matches the number of attempts
# Plotting the results
plt.plot(y, times, marker='o', linestyle='-', color='b')
plt.xlabel("Attempt Number")
plt.ylabel("Time Taken (seconds)")
plt.title("Typing Test Evaluation")
plt.grid()
# Printing results
print(f"You have made {mistake} mistakes.")
print("Your test evaluation is loading...")
t.sleep(2) # Adding a slight delay for effect
plt.show()
import time as t
time_now=t.localtime()
print("transaction completed at:",str(time_now.tm_hour)+":"+str(time_now.tm_min)+":"+str(time_now.tm_sec))
print(str(time_now.tm_mday)+"-"+str(time_now.tm_mon)+"-"+str(time_now.tm_year))
t.sleep(2)
time_niw=t.time()
delivery_time=time_niw+(86400*7)
#print(t.localtime(delivery_time))
print("Delivery on "+str(time_now.tm_mday)+"-"+str(time_now.tm_mon)+"-"+str(time_now.tm_year))
x = 0
people=[]
while x<5:
person =input("Type the name of a person:")
people.append(person)
x += 1
print(people)
# This is main.py, a script that will use the custom module 'my_module.py'.
# It demonstrates how to import and use components (functions, classes, variables)
# from another Python file in the same directory (or a directory in Python's search path).
# --- What is a Module? ---
# A module is simply a Python file (.py extension) containing Python definitions and statements.
# Modules help you organize your code into logical units, making it:
# - More manageable: Break down large programs into smaller, well-defined pieces.
# - Reusable: Use the same functions or classes in multiple scripts without copying code.
# - Shareable: Distribute your code for others to use.
# 'my_module.py' in this directory is an example of a custom module we've created.
print("--- main.py execution started ---")
# When Python encounters an `import` statement, it looks for the specified module.
# If it's the first time this module is imported in the program, Python will:
# 1. Execute the module file (my_module.py in this case) from top to bottom.
# This means any statements not inside a function or class, or the `if __name__ == "__main__":`
# block in the module, will run. (You should see "my_module.py is being imported..." printed).
# 2. Make the module's objects (functions, classes, variables) available to main.py.
# --- 1. Importing the entire module ---
# `import my_module` imports everything from my_module.py under the namespace 'my_module'.
# To access its components, you need to prefix them with `my_module.`.
print("\n--- Method 1: import my_module ---")
import my_module # This executes my_module.py (if not already executed)
# Using the greet function from my_module
message1 = my_module.greet("Alice")
print(f"From my_module.greet: {message1}")
# Using the add function from my_module
sum1 = my_module.add(100, 200)
print(f"From my_module.add(100, 200): {sum1}")
# Accessing the global variable from my_module
print(f"Accessing my_module.MODULE_VERSION: {my_module.MODULE_VERSION}")
# Creating an instance of MyHelperClass from my_module
helper1 = my_module.MyHelperClass("Main Script User 1")
print(helper1.get_info())
# --- 2. Importing specific components using `from ... import ...` ---
# This imports specific names directly into the current script's namespace.
# You don't need to prefix them with the module name.
print("\n--- Method 2: from my_module import greet ---")
from my_module import greet # Only imports the 'greet' function
# Now 'greet' can be called directly
message2 = greet("Bob") # This 'greet' is my_module.greet
print(f"From imported greet: {message2}")
# Note: If main.py had its own 'greet' function, this import would shadow (replace) it
# if 'greet' was defined *before* this import, or be shadowed by it if defined *after*.
# Trying to access 'add' without prefixing or specific import will fail here:
# sum2 = add(5,5) # This would cause a NameError because 'add' is not directly in main.py's namespace yet
# --- 3. Importing a specific component with an alias using `as` ---
# This imports a specific name but gives it a different name (alias) in the current script.
# Useful to avoid naming conflicts or to use a shorter name.
print("\n--- Method 3: from my_module import add as custom_add ---")
from my_module import add as custom_add
sum3 = custom_add(7, 8)
print(f"Result of custom_add(7, 8): {sum3}")
# print(add(7,8)) # This would still cause a NameError as 'add' itself was not directly imported
# --- 4. Importing multiple specific components (including classes and variables) ---
print("\n--- Method 4: from my_module import MyHelperClass, MODULE_VERSION ---")
from my_module import MyHelperClass, MODULE_VERSION
# Now MyHelperClass and MODULE_VERSION can be used directly
helper2 = MyHelperClass("Main Script User 2")
print(helper2.get_info())
print(f"Directly imported MODULE_VERSION: {MODULE_VERSION}")
# --- Understanding `if __name__ == "__main__":` in `my_module.py` ---
# Each Python file has a special built-in variable called `__name__`.
# - When a Python script is run directly (e.g., `python my_module.py`), its `__name__` variable
# is set to `"__main__"`.
# - When a Python script is imported as a module into another script (like we are doing here
# with `my_module.py`), its `__name__` variable is set to the name of the module file
# (i.e., `"my_module"` for `my_module.py`).
# The `if __name__ == "__main__":` block in `my_module.py` contains code that will
# ONLY run if `my_module.py` is executed directly. It will NOT run when `my_module.py`
# is imported by `main.py` (because in that case, `my_module.__name__` is "my_module", not "__main__").
# You should have seen the print statement "my_module.py is being imported or executed."
# from `my_module.py` when this script started (due to the first import).
# However, you should NOT have seen the print statement from inside the
# `if __name__ == "__main__":` block of `my_module.py`.
# To see that, you would need to run `python custom_module_example/my_module.py` from your terminal.
print("\n--- Demonstrating that my_module's __name__ is 'my_module' when imported ---")
# We can even access the __name__ variable of the imported module (though not typical)
if 'my_module' in dir(): # Check if my_module was imported using "import my_module"
print(f"The __name__ variable of the imported my_module is: {my_module.__name__}")
# --- Best Practices for Importing ---
# - Be specific: `from module import specific_function` is often preferred over `import module`
# if you only need a few things, as it makes it clearer where names come from.
# - Avoid `from module import *`: This imports all names from the module into the current
# namespace. It can make it hard to tell where a function or variable came from and
# can lead to naming conflicts. There are exceptions, but generally, it's discouraged for clarity.
# - Use aliases (`as`) for clarity or to resolve naming conflicts.
# - Place imports at the top of your script (standard convention).
print("\n--- main.py execution finished ---")
# To run this example:
# 1. Make sure both `main.py` and `my_module.py` are in the `custom_module_example` directory.
# 2. Open your terminal.
# 3. Navigate to the `custom_module_example` directory.
# 4. Run this script using the command: `python main.py`
#
# You can also run the module directly to see its `if __name__ == "__main__":` block execute:
# `python my_module.py`
# This is a Python module named 'my_module'.
# A module is simply a Python file with a .py extension that contains Python definitions and statements.
# Modules are used to organize code into logical units, making it more manageable, reusable, and shareable.
print("my_module.py is being imported or executed.")
# --- 1. Global Variable ---
# This is a variable defined at the module level.
# It can be imported and accessed by other scripts that import this module.
MODULE_VERSION = "1.0"
# --- 2. Functions ---
# Functions defined in a module can be imported and used in other scripts.
def greet(name):
"""
A simple function that returns a greeting string.
Args:
name (str): The name of the person to greet.
Returns:
str: A greeting message.
"""
return f"Hello, {name}! Welcome from my_module."
def add(a, b):
"""
A simple function that adds two numbers.
Args:
a (int or float): The first number.
b (int or float): The second number.
Returns:
int or float: The sum of a and b.
"""
return a + b
# --- 3. Class ---
# Classes defined in a module can also be imported and used to create objects.
class MyHelperClass:
"""
A simple example class within the module.
"""
def __init__(self, owner_name="DefaultOwner"):
"""
Constructor for MyHelperClass.
Args:
owner_name (str): The name of the owner of this helper instance.
"""
self.owner_name = owner_name
print(f"MyHelperClass instance created by {self.owner_name}.")
def get_info(self):
"""
A method that returns some information about the instance.
Returns:
str: Information string.
"""
return f"This is a MyHelperClass object, owned by {self.owner_name}. Module version: {MODULE_VERSION}"
# --- 4. The `if __name__ == "__main__":` block ---
# This block of code is executed only when the module is run directly as a script
# (e.g., by typing `python my_module.py` in the terminal).
# It is NOT executed when the module is imported into another script.
# This is useful for including test code or a demonstration of the module's capabilities
# that should only run when the module itself is the main program.
if __name__ == "__main__":
# This code runs ONLY if you execute `python custom_module_example/my_module.py`
print("\n--- my_module.py executed directly ---")
print("This part of the script runs because __name__ is currently '__main__'.")
# Example usage of the module's components when run directly:
print("\nDirect execution examples:")
current_version = MODULE_VERSION
print(f"Module Version (accessed directly): {current_version}")
greeting_message = greet("Developer")
print(greeting_message)
sum_result = add(10, 5)
print(f"Result of add(10, 5): {sum_result}")
helper_instance = MyHelperClass("Direct Script User")
print(helper_instance.get_info())
print("\n--- End of my_module.py direct execution ---")
# When this file is imported by another script (like main.py):
# - The initial print statement ("my_module.py is being imported...") will run.
# - Definitions (MODULE_VERSION, greet, add, MyHelperClass) will be loaded.
# - The code inside `if __name__ == "__main__":` will NOT run.
# In that case, __name__ for this file will be "my_module" (the name of the module).
# This file makes the 'tests' directory a Python package.
# It can be empty.
import unittest
import sys
import os
# Add the parent directory (project root) to the Python path
# This allows us to import modules from the root directory (e.g., 'functions.py')
# when running tests from the 'tests' subdirectory.
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.insert(0, project_root)
# Now we can import from functions.py
# If functions.py is not found, it might indicate the script is not being run from the correct context,
# or that functions.py is missing from the root of the project.
try:
from functions import fahrtocelsius, say_hello_simple, say_hello_adv
except ImportError:
print("Error: functions.py not found. Ensure it's in the project root and sys.path is correct.")
# As a fallback for environments where path manipulation might be tricky,
# one could define dummy functions here, but the goal is to test the actual functions.
# For now, we'll let the ImportError halt if it occurs, as it's a setup issue.
raise
class TestFunctions(unittest.TestCase):
"""
Test cases for the functions defined in functions.py.
"""
# --- Tests for fahrtocelsius ---
def test_fahrtocelsius_freezing_point(self):
"""Test fahrtocelsius with the freezing point of water (32 F = 0 C)."""
self.assertEqual(fahrtocelsius(32), 0)
def test_fahrtocelsius_boiling_point(self):
"""Test fahrtocelsius with the boiling point of water (212 F = 100 C)."""
self.assertEqual(fahrtocelsius(212), 100)
def test_fahrtocelsius_negative_value(self):
"""Test fahrtocelsius with a common negative value (-40 F = -40 C)."""
self.assertEqual(fahrtocelsius(-40), -40)
def test_fahrtocelsius_other_value(self):
"""Test fahrtocelsius with another arbitrary value (e.g., 50 F = 10 C)."""
self.assertEqual(fahrtocelsius(50), 10)
# --- Tests for say_hello_simple ---
# These tests assume say_hello_simple has been refactored to RETURN a string.
def test_say_hello_simple_with_name(self):
"""Test say_hello_simple with a typical name."""
expected_output = "Hello Alice, How are you"
self.assertEqual(say_hello_simple("Alice"), expected_output)
def test_say_hello_simple_empty_string(self):
"""Test say_hello_simple with an empty string as name."""
expected_output = "Hello , How are you"
self.assertEqual(say_hello_simple(""), expected_output)
# --- Tests for say_hello_adv ---
# These tests assume say_hello_adv has been refactored to RETURN a string.
def test_say_hello_adv_one_argument(self):
"""Test say_hello_adv with only the first argument (person2 should use default)."""
expected_output = "Hello Bob, How are you? And hello to mafia!"
self.assertEqual(say_hello_adv("Bob"), expected_output)
def test_say_hello_adv_two_arguments(self):
"""Test say_hello_adv with both arguments provided."""
expected_output = "Hello Charlie, How are you? And hello to friend!"
self.assertEqual(say_hello_adv("Charlie", "friend"), expected_output)
def test_say_hello_adv_two_arguments_one_empty(self):
"""Test say_hello_adv with the second argument being an empty string."""
expected_output = "Hello Dave, How are you? And hello to !"
self.assertEqual(say_hello_adv("Dave", ""), expected_output)
if __name__ == '__main__':
"""
This allows the test script to be run directly from the command line.
`unittest.main()` will discover and run all tests in this file.
"""
unittest.main()
import unittest
import sys
import os
# Add the parent directory (project root) to the Python path
# This allows us to import modules from the root directory (e.g., 'oop_concepts.py')
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.insert(0, project_root)
# Now we can import from oop_concepts.py
# We will test the Dog class and its related functionalities.
try:
from oop_concepts import Dog, GoldenRetriever # Assuming these classes exist
except ImportError:
print("Error: oop_concepts.py not found or classes missing. Ensure it's in the project root.")
# Define dummy classes if the import fails, to allow test structure to be checked,
# but ideally, the import should work.
class Dog:
species = "Canis familiaris"
def __init__(self, name, age):
self.name = name
self.age = age
def description(self): return ""
def speak(self, sound): return ""
class GoldenRetriever(Dog):
def __init__(self, name, age, favorite_toy):
super().__init__(name,age)
self.favorite_toy = favorite_toy
def fetch(self, item): return ""
# In a real scenario, we would want the test to fail if the import fails.
raise
class TestOopConcepts(unittest.TestCase):
"""
Test cases for classes defined in oop_concepts.py.
Focusing on the Dog and GoldenRetriever classes.
"""
# --- Tests for Dog Class ---
def test_dog_creation(self):
"""Test if a Dog object can be created successfully."""
dog = Dog("Buddy", 3)
self.assertIsNotNone(dog, "Dog object should not be None")
self.assertIsInstance(dog, Dog, "Object should be an instance of Dog")
def test_dog_attributes(self):
"""Test if the Dog object has the correct attributes after creation."""
dog_name = "Rex"
dog_age = 5
dog = Dog(dog_name, dog_age)
self.assertEqual(dog.name, dog_name, f"Dog name should be {dog_name}")
self.assertEqual(dog.age, dog_age, f"Dog age should be {dog_age}")
self.assertEqual(dog.species, "Canis familiaris", "Dog species class attribute should be 'Canis familiaris'")
def test_dog_description_method(self):
"""Test the description method of the Dog class."""
dog = Dog("Lucy", 4)
expected_description = "Lucy is 4 years old."
self.assertEqual(dog.description(), expected_description)
def test_dog_speak_method(self):
"""Test the speak method of the Dog class."""
dog = Dog("Max", 2)
sound_to_make = "Woof"
expected_output = f"Max says {sound_to_make}!"
self.assertEqual(dog.speak(sound_to_make), expected_output)
# --- Tests for GoldenRetriever Class (Inheritance) ---
def test_goldenretriever_creation(self):
"""Test if a GoldenRetriever object can be created."""
gr = GoldenRetriever("Charlie", 2, "ball")
self.assertIsNotNone(gr, "GoldenRetriever object should not be None")
self.assertIsInstance(gr, GoldenRetriever, "Object should be an instance of GoldenRetriever")
self.assertIsInstance(gr, Dog, "GoldenRetriever object should also be an instance of Dog (inheritance)")
def test_goldenretriever_attributes(self):
"""Test attributes of GoldenRetriever, including inherited ones."""
gr_name = "Goldie"
gr_age = 1
gr_toy = "Frisbee"
gr = GoldenRetriever(gr_name, gr_age, gr_toy)
self.assertEqual(gr.name, gr_name)
self.assertEqual(gr.age, gr_age)
self.assertEqual(gr.favorite_toy, gr_toy, f"Favorite toy should be {gr_toy}")
self.assertEqual(gr.species, "Canis familiaris", "Species should be inherited from Dog")
def test_goldenretriever_fetch_method(self):
"""Test the fetch method specific to GoldenRetriever."""
gr = GoldenRetriever("Sunny", 3, "squeaky toy")
item_to_fetch = "stick"
expected_output = f"Sunny fetches the {item_to_fetch}. Their favorite toy is squeaky toy."
self.assertEqual(gr.fetch(item_to_fetch), expected_output)
def test_goldenretriever_speak_method_overridden(self):
"""Test the overridden speak method in GoldenRetriever."""
gr = GoldenRetriever("Rocky", 4, "rope")
# Default sound for GoldenRetriever's overridden speak method
expected_output_default = "Rocky (a Golden Retriever) enthusiastically says Bark!"
self.assertEqual(gr.speak(), expected_output_default)
# Specific sound
sound_to_make = "Awooo"
expected_output_specific = f"Rocky (a Golden Retriever) enthusiastically says {sound_to_make}!"
self.assertEqual(gr.speak(sound_to_make), expected_output_specific)
if __name__ == '__main__':
"""
Allows running the tests directly from the command line.
"""
unittest.main()