Python Basics Warp Up
Python Basics Warp Up
Python Basics Warp Up
• Conditional statements
• Loops
• Functions
• Importing modules and standard library
Integers: These are whole numbers like we have three numbers: ten, zero, and negative fifty. In
Python, you would write these as: ten comma zero comma or negative fifty. They’re useful for
counts or math operations.
Floats: These are decimal numbers like we have two floating point numbers: three point one
four and negative forty-two point five. In Python, you would write these as: three point one four
or negative forty-two point five They’re also useful for math operations that require precision.
Strings: These represent text and are surrounded by single or double quotes. We can
concatenate strings too: 'Hello ’ plus the string ‘world!’. In Python, you would write this as: quote
Hello space single or double quotes plus single or double quotes world exclamation mark single
or double quotes.gives us the string ‘Hello world!’. In Python, you would write this as: quote
Hello space world exclamation mark single or double quotes.
Booleans: These are True or False values representing logical or comparison operations.
Lists: These are ordered sequences enclosed in square brackets like we have a list of three
numbers: one, two, and three. In Python, you would write this as: open square bracket one
comma two comma three close square bracket. Lists can contain different data types.
Tuples: These are like lists but are immutable once declared.
name = "Sarah"
age = "Thirty" # Type is now string instead of integer
Now let's go over the main data types we can store in variables:
- Integers are whole numbers like 10, 0, -50. Useful for counts or
math.
- Floats are decimal numbers like 3.14, -42.5. Also useful for math
operations.
```python
age = 16
if age < 0:
print("Invalid age!")
elif age < 18:
print("You are a minor.")
elif age >= 65:
print("You are a senior citizen.")
```
```python
is_citizen = True
age = 19
# Indexing/Slicing:
my_list = [10, 20, 30, 40]
print(my_list[0]) # prints 10
print(my_list[:2]) # prints [10, 20]
# Append/Insert:
my_list.append(50)
print(my_list) # prints [10, 20, 30, 40, 50]
my_list.insert(1, 15)
print(my_list) # prints [10, 15, 20, 30, 40, 50]
# Delete/Pop:
del my_list[1]
print(my_list) # prints [10, 20, 30, 40, 50]
last_element = my_list.pop()
print(last_element) # prints 50
# Sort/Reverse:
my_list.sort()
print(my_list) # prints [10, 20, 30, 40]
my_list.reverse()
print(my_list) # prints [40, 30, 20, 10]
# Indexing/Slicing:
print(my_tuple[0]) # prints 1
# Changing Values:
my_dict['age'] = 31
print(my_dict) # prints {'name': 'John Doe', 'age': 31}
# Adding Items:
my_dict['profession'] = 'Engineer'
print(my_dict) # prints {'name': 'John Doe', 'age': 31, 'profession':
'Engineer'}
# Removing Items:
my_dict.pop('profession')
print(my_dict) # prints {'name': 'John Doe', 'age': 31}
# clear() Method:
my_dict = {'name': 'John Doe', 'age': 30}
my_dict.clear()
print(my_dict) # prints {}
# get() Method:
value = my_dict.get('name')
print(value) # prints 'John Doe'
# items() Method:
items = my_dict.items()
print(items) # prints dict_items([('name', 'John Doe'), ('age', 30)])
# keys() Method:
keys = my_dict.keys()
print(keys) # prints dict_keys(['name', 'age'])
# values() Method:
values = my_dict.values()
print(values) # prints dict_values(['John Doe', 30])
# update() Method:
my_dict.update({'profession': 'Engineer'})
print(my_dict) # prints {'name': 'John Doe', 'age': 30, 'profession':
'Engineer'}
# Indexing/Slicing:
my_list = [10, 20, 30, 40]
print(my_list[0]) # prints 10
print(my_list[:2]) # prints [10, 20]
# String Operations:
str1 = "Hello, "
str2 = "World!"
str3 = str1 + str2
print(str3) # prints 'Hello, World!
# Repetition:
repeat_str = "Python! " * 3
print(repeat_str) # prints 'Python! Python! Python!
# Concatenation:
greeting = "Hello"
name = "John"
message = greeting + " " + name
print(message) # Output: "Hello John"
# Length:
text = "Python is amazing"
length = len(text)
print(length) # Output: 1
# Indexing:
word = "Python"
first_letter = word[0]
print(first_letter) # Output: "P"
# strip():
# The strip() method removes any leading or trailing whitespace from a
string. For example:
text = " Python "
print(text.strip()) # Output: "Python"
x = -10
print(abs(x)) # prints '10'
s = "Hello, World!"
print(len(s)) # prints '13'
s = "Hello, World!"
x = "World"
print(s.index(x)) # prints '7'
for i in range(len(fruits)):
print(i, fruits[i])
for a, b in tuples:
print(a, b)
Next, let's discuss the start, stop, and step arguments we can pass to
range() to customize our loops.
python
for i in range(10, 0, -1):
print(i) # Prints 10 9 8 7 ... 3 2 1
for i in range(5):
if i == 3:
break
else:
print("Loop completed without breaking")
The else block executes after the for loop finishes if it doesn't
encounter a break statement.
values = [1, 2, 3, 4]
for v in values:
values.remove(v)
for v in values[:]:
values.remove(v)
Or iterate backwards:
for v in reversed(values):
values.remove(v)
numbers = [1, 2, 3, 4, 5, 6]
even_numbers = []
for n in numbers:
if n % 2 == 0:
even_numbers.append(n)
Now let's look at how we can use break and continue statements inside
loops:
for i in range(10):
if i == 5:
break
print(i)
for i in range(10):
if i % 2 != 0:
continue
print(i)
for i in range(len(fruits)):
print(fruits[i])
squared = []
for x in range(10):
squared.append(x**2)
keep_going = True
while keep_going and x < 10:
print(x)
x += 1
process(x)
"""
# The else block runs if the loop exits normally without hitting
break: Avoiding infinite loops
#Make sure to update loop conditions properly:
"""
x = 0
while x < 5:
print(x)
"""
# Forgot to update x, so infinite loop
# Incrementing/Decrementing
#Use a pattern like:
"""
while value < max_value:
value += 1
"""
#Rather than:
"""
value = 0
while value < max_value:
value = value + 1 # Don't do this!
"""
# do while Pattern:
#Perform at least one iteration using do while:
"""
do:
print("Loop body")
while condition
list = [1, 2, 3]
i = 0
while i < len(list):
print(list[i])
i += 1
# Counter Loop:
# Use a counting variable to complete a certain number of iterations:
count = 0
while count < 10:
print(count)
count += 1
# Input Loop:
# Loop while user input is valid:
"""
while True:
input = get_input()
if is_valid(input):
process(input)
else:
break
"""
# Event Loop:
# Loop while waiting for events:
"""
while True:
event = get_next_event()
if event is None:
break
process_event(event)
"""
# This is very common in GUIs.
# Conditional Loop:
# Loop while some condition holds true:
"""
while temp > threshold:
cooler.run()
temp = read_temp()
"""
#Combining Conditions:
# Use and/or to require multiple conditions:
while x < 10 and y > 3:
x += 1
y -= 1
print(x,y)
# Iterative Approach:
def factorial(n):
result = 1
for i in range(2, n+1):
result *= i
return result
# And recursion Approach:
def factorial(n):
if n == 1:
return 1
return n * factorial(n-1)
# Do this:
index = 0
total = 0
# Not this:
while index < 10:
total = 0 # Don't initialize here
total += index
index = 0 # Set initial value here
index += 1
For loop counters and other temporary vars, use names like i, j, etc:
i = 0
while i < 10:
print(i)
i += 1
while True:
print("Infinite Loop!")
Set a max iteration count or check conditions that will become false.
while True:
if cond1:
continue
if cond2:
break
do_something()
# Good
total = 0
while x < 10:
total += x
print(total)
# Avoid
while x < 10:
print(total)
total += x
while data:
process(data)
Instead of:
while True:
data = load_data() # Don't reload each time
process(data)
Some types like deque are faster than lists for queues/stacks.
Preallocate arrays
while True:
item = get_next()
process_item(item)
Recursion
def factorial(n):
if n == 1:
return 1
else:
return n * factorial(n-1)
For loops
for i in range(10):
print(i)
1. Defining Functions: In Python, we define functions using the def keyword, followed by
the function name and parentheses. Let's see an example:
def greet():
print("Hello, everyone!")
In the example above, we define a function named greet() that prints a greeting message. We
can call the function by using its name followed by parentheses.
1. Function Parameters: Functions can accept parameters, which are placeholders for
values passed into the function. Parameters are defined inside the parentheses of the
function definition. Let's see an example:
def greet(name):
print(f"Hello, {name}!")
In the example above, we define a function named greet() that takes a name parameter. We
can pass different values to the function when calling it.
1. Return Statement: Functions can also return values using the return statement. The
returned value can be stored in a variable or used directly. Let's see an example:
def add(a, b):
return a + b
result = add(2, 3)
print(result) # Output: 5
In the example above, we define a function named add() that takes two parameters, a and b,
and returns their sum. We assign the returned value to the result variable and print it.
Great job! In this lecture, we explored the basics of functions in Python. We learned how to
define functions, use parameters to accept input, and use the return statement to provide
output. Functions are a powerful tool for organizing and reusing code, and they play a crucial
role in writing clean and modular programs.
2. Base Case: The base case is the condition that determines when the recursive
function should stop calling itself. It provides a termination condition to prevent
infinite recursion. Without a base case, the function would keep calling itself
indefinitely. Let's see an example:
def countdown(n):
if n == 0:
print("Blastoff!")
else:
print(n)
countdown(n - 1)
1. Recursive Case: The recursive case is the part of the function where it calls itself with a
modified input. It breaks down the problem into a smaller version of itself. Let's see an
example:
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n - 1)
result = factorial(5)
print(result) # Output: 120
In the example above, we define a recursive function named factorial() that calculates the
factorial of a number n. The recursive case multiplies n with the factorial of n - 1 until n
reaches 0, which is the base case.
1. Function Decorators:
Function decorators are a way to modify the behavior of a function
without changing its source code. They are defined using the
`@decorator_name` syntax above the function definition. Let's see an
example:
```python
def uppercase_decorator(func):
def wrapper():
result = func().upper()
return result
return wrapper
@uppercase_decorator
def greet():
return "hello"
2. Higher-Order Functions:
Higher-order functions are functions that take one or more functions
as arguments or return functions as their results. They enable us to
write more flexible and reusable code. Let's see an example:
```python
def multiply_by(n):
def multiplier(x):
return x * n
return multiplier
double = multiply_by(2)
triple = multiply_by(3)
print(double(5)) # Output: 10
print(triple(5)) # Output: 15
Function Caching and Memoization: These techniques allow us to optimize the performance of
functions by storing and reusing previously computed results. Let's dive in!
1. Function Caching: Function caching is a technique where the results of a function call are
stored in memory for future use. If the samefunction is called again with the same
arguments, the cached result is returned instead of recomputing the function. Let's see
an example using the functools module:
import functools
@functools.lru_cache()
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(10)) # Output: 55
print(fibonacci(15)) # Output: 610
In the example above, we define a recursive function fibonacci() that calculates the
Fibonacci sequence. By applying the @functools.lru_cache() decorator, the function's
results are cached, allowing subsequent calls with the same arguments to be retrieved from the
cache.
def wrapper(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return wrapper
@memoize
def factorial(n):
if n <= 1:
return 1
return n * factorial(n - 1)
In the example above, we define a memoization decorator memoize() that stores the results of
the decorated function factorial() in a cache dictionary. If the same arguments are
encountered again, the cached result is returned.
Function caching and memoization are powerful techniques to optimize the performance of
functions, especially when dealing with computationally expensive tasks or recursive
algorithms.