# example of enumeration with list-
flavor_list = ['vanilla', 'chocolate', 'pecan', 'strawberry']
for flavor in flavor_list:
print(f'{flavor} is delicious')vanilla is delicious
chocolate is delicious
pecan is delicious
strawberry is delicious
Python basics
Kunal Khurana
December 6, 2023
# iterating over lenght of lists
longest_name = None
max_count = 0
for i in range(len(names)):
count = counts[i]
if count > max_count:
longest_name = names[i]
max_count = count
print(longest_name)pricila
# we see that the above code is a bit noisy.
# to imporve it, we'll use the enumerate method
for i, name in enumerate(names):
count = counts[i]
if count > max_count:
longest_name = name
max_count = count
print(longest_name)pricila
# to improve it further, we'll use the inbuilt zip function
for name, count in zip(names, counts):
if count > max_count:
longest_name = name
max_count = count
print(longest_name)pricila
Loop 0
Loop 1
Loop 2
Else block!
# using break in the code
for i in range(3):
print('Loop', i)
if i == 1:
break
else:
print('Else block!')Loop 0
Loop 1
# else runs immediately if looped over an empty sequence
for x in []:
print('Never runs')
else:
print('For else block!')For else block!
# Example sequence
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Using slicing to get a portion of the sequence
subset = numbers[2:8]
# Using unpacking to assign values to variables
first, *middle, last = subset # *used for extended unpacking
# Print the results
print("Subset:", subset)
print("First element:", first)
print("Middle elements:", middle)
print("Last element:", last)Subset: [3, 4, 5, 6, 7, 8]
First element: 3
Middle elements: [4, 5, 6, 7]
Last element: 8
class Tool:
def __init__(self, name, weight):
self.name = name
self.weight = weight
def __repr__(self):
return f'Tool({self.name}, {self.weight})'
# Example usage of the Tool class
tools = [
Tool('level', 3.5),
Tool('hammer', 1.25),
Tool('screwdriver', 0.5),
Tool('chisel', 0.25),
]
# tools.sort() #this will give us a traceback
# Display the unsorted list of tools
print('Unsorted:')
for tool in tools:
print(repr(tool))
# Sort the tools based on their names
tools.sort(key=lambda x: x.name)
# Display the sorted list of tools
print('\nSorted:')
for tool in tools:
print(tool)Unsorted:
Tool(level, 3.5)
Tool(hammer, 1.25)
Tool(screwdriver, 0.5)
Tool(chisel, 0.25)
Sorted:
Tool(chisel, 0.25)
Tool(hammer, 1.25)
Tool(level, 3.5)
Tool(screwdriver, 0.5)
# cutest baby animal
votes = {
'otter': 1281,
'polar bear': 587,
'fox': 863,
}
# save the rank to an empty dictionary
def populate_ranks(votes, ranks): #takes votes and ranks dictionary
names = list(votes.keys())
names.sort(key=votes.get, reverse=True)
for i, name in enumerate(names, 1):
ranks[name] = i
# function that returs the animal with hightest rank
def get_winner(ranks):
return next(iter(ranks))
# results
ranks = {}
populate_ranks(votes, ranks)
print(ranks)
winner = get_winner(ranks)
print(winner){'otter': 1, 'fox': 2, 'polar bear': 3}
otter
#2) ‘KeyError’ method key = ‘wheat’
try: count = bread[key] except KeyError: count = 0
bread[key] = count + 1
# more complex dictionary, to know who voted for which type of bread
votes = {
'14grain' : ['Bob', 'Ashley', 'Suzan', 'Susan'],
'multigrain' : ['Dikshita', 'Kavya'],
'wheat' : ['Bhavna', 'Shristi'],
'oats' : ['Nikumbh']
}
key = 'kinoa'
who = 'Raph'
if key in votes:
names = votes[key]
else:
votes[key] = names = []
names.append(who)
print (votes){'14grain': ['Bob', 'Ashley', 'Suzan', 'Susan'], 'multigrain': ['Dikshita', 'Kavya'], 'wheat': ['Bhavna', 'Shristi'], 'oats': ['Nikumbh'], 'kinoa': ['Raph']}
# try except
try:
names = votes[key]
except KeyError:
votes[key] = names =[]
names.append(who)
print(votes){'14grain': ['Bob', 'Ashley', 'Suzan', 'Susan'], 'multigrain': ['Dikshita', 'Kavya'], 'wheat': ['Bhavna', 'Shristi'], 'oats': ['Nikumbh'], 'kinoa': ['Raph', 'Raph', 'Raph']}
# get method
names = votes.get(key)
if names is None:
votes[key] = names = []
names.append(who)
print(votes){'14grain': ['Bob', 'Ashley', 'Suzan', 'Susan'], 'multigrain': ['Dikshita', 'Kavya'], 'wheat': ['Bhavna', 'Shristi'], 'oats': ['Nikumbh', 'Raph', 'Raph', 'Raph', 'Raph'], 'kinoa': ['Raph', 'Raph', 'Raph']}
# prevent repetition
if (names := votes.get(key)) is None:
votes[key] = names = []
names.append(who)
print(votes){'14grain': ['Bob', 'Ashley', 'Suzan', 'Susan'], 'multigrain': ['Dikshita', 'Kavya'], 'wheat': ['Bhavna', 'Shristi'], 'oats': ['Nikumbh', 'Raph', 'Raph', 'Raph', 'Raph', 'Raph', 'Raph'], 'kinoa': ['Raph', 'Raph', 'Raph']}
# list of countires and cities visited
visits = {
'India' : {'Punjab', 'Rajastan', 'Goa', 'Himachal Pardesh', 'Haryana'},
'UAE' : {'Dubai'},
'Nepal' : {'Kathmandu'},
'Canada' : {'Québec', 'Ontario'},
}
# using setdefalut method to add to the list (method 1)
visits.setdefault('France', set()).add('Remi') #short
if (japan := visits.get('Japan')) is None: #long
visits['Japan'] = japan = set()
japan.add('Kyoto')
print(visits){'India': {'Rajastan', 'Haryana', 'Punjab', 'Himachal Pardesh', 'Goa'}, 'UAE': {'Dubai'}, 'Nepal': {'Kathmandu'}, 'Canada': {'Ontario', 'Québec'}, 'France': {'Remi'}, 'Japan': {'Kyoto'}}
# how about i create a class then add places
from collections import defaultdict
class Visits:
def __init__(self):
self.data = defaultdict(set)
def add(self, country, city):
self.data[country].add(city)
visits = Visits()
visits.add('England', 'Bath')
visits.add('England', 'London')
print(visits.data)defaultdict(<class 'set'>, {'England': {'Bath', 'London'}})
# Function returning multiple values
def get_person_details():
name = "John"
age = 30
city = "Montréal"
gender = "Male"
return name, age, city, gender
# Unpacking with three variables
name, age, city = get_person_details() #return 3
variables
# Displaying the results
print("Name:", name)
print("Age:", age)
print("City:", city)ValueError: too many values to unpack (expected 3)
# Function returning multiple values
def get_person_details():
name = "John"
age = 30
city = "Montréal"
#gender = "Male"
return name, age, city
# Unpacking with three variables
name, age, city = get_person_details() #3 return variables
# Displaying the results
print("Name:", name)
print("Age:", age)
print("City:", city)Name: John
Age: 30
City: Montréal
# Function that returns None on failure
def divide_numbers(a, b):
if b == 0:
return None # Indicating failure by returning None
else:
return a / b
# Using the function and checking for failure with None
result = divide_numbers(10, 2)
if result is not None:
print("Result:", result)
else:
print("Error: Cannot divide by zero.")
# Using the function and checking for failure with None
result = divide_numbers(10, 0)
if result is not None:
print("Result:", result)
else:
print("Error: Cannot divide by zero.")Result: 5.0
Error: Cannot divide by zero.
# Function that raises an exception on failure
def divide_numbers(a, b):
if b == 0:
raise ValueError("Cannot divide by zero")
else:
return a / b
# Using the function and handling the exception
try:
result = divide_numbers(10, 2)
print("Result:", result)
except ValueError as e:
print("Error:", e)
# Using the function and handling the exception
try:
result = divide_numbers(10, 0)
print("Result:", result)
except ValueError as e:
print("Error:", e)Result: 5.0
Error: Cannot divide by zero
class Sorter:
def __init__(self, group):
self.group = group
self.found = False
def __call__(self, x):
if x in self.group:
self.found = True
return (0, x)
else:
return (1, x)
# Example usage
group = {2, 4, 6}
numbers = [5, 3, 2, 1, 4]
sorter = Sorter(group)
numbers.sort(key=sorter)
# Display the sorted list
print("Sorted List:", numbers)
# Check if any item from the group is found during sorting
assert sorter.found is TrueSorted List: [2, 4, 1, 3, 5]
*args is not suggested for two reasons-
1) Optional positional arguments are always turned into a tuple before they are passed to a function. Uses a lot of memory and could crash a function.
2) Doesn't provide value inclusive of the new argument. Hence, no use of adding an additional argument.
# Original function with *args
def example_function(*args):
# Existing functionality using args
total = sum(args)
return total
# Example usage
result = example_function(1, 2, 3)
print("Result:", result)
# Attempt to add a new positional argument
# This would break existing callers
def updated_function(new_arg, *args):
total = sum(args) + new_arg
return total
result2 = updated_function(4,5)
print('Result2:', result2)Result: 6
Result2: 9
from datetime import datetime
def log_message(message, timestamp=None):
"""
Log a message with an optional timestamp.
Parameters:
- message (str): The message to be logged.
- timestamp (datetime, optional): The timestamp for the log message.
Defaults to the current time if not provided.
"""
if timestamp is None:
timestamp = datetime.now()
print(f"{timestamp}: {message}")
# Example usage
log_message("Error occurred") # Logs the message with the current timestamp
log_message("Warning", timestamp=datetime(2023, 1, 1)) # Logs the message with a specific timestamp2023-12-05 18:49:25.657917: Error occurred
2023-01-01 00:00:00: Warning
example_function((3, 4), {}) -> 12