100 Days of Data Engineering Day 5: Python
Python Tutorial: Lists, Tuples, and Loops, Functions, Mutability, Error Handling
1. Lists
A list in Python is a collection of items that can be changed (mutable), and can contain elements of different types. Here’s how you can work with lists:
- Creating a list: Lists are defined by square brackets
[]
with items separated by commas.
my_list = [1, 2, 3, "Python", True]
- Accessing elements: You can access elements by their index, starting from 0.
print(my_list[0]) # Output: 1
print(my_list[3]) # Output: Python
- Adding elements: Use
append()
to add elements to the end of a list.
my_list.append("new item")
print(my_list) # Output: [1, 2, 3, 'Python', True, 'new item']
- Removing elements: Use
remove()
to remove specific elements orpop()
to remove an element at a specific index.
my_list.remove("Python")
my_list.pop(1)
print(my_list) # Output: [1, 3, True, 'new item']
- Looping through a list: You can loop through each item in a list using a
for
loop.
for item in my_list:
print(item)
2. Tuples
Tuples are similar to lists but are immutable (cannot be changed after creation). They are defined by parentheses ()
.
- Creating a tuple:
my_tuple = (1, 2, 3, "Python")
- Accessing elements:
print(my_tuple[2]) # Output: 3
- Immutability: Trying to change a tuple after it’s created will result in an error.
# my_tuple[1] = 4 # This would raise an error
- Looping through a tuple:
for item in my_tuple:
print(item)
3. Loops
Loops in Python are used to iterate over a sequence of items.
for
loop: Used to iterate over a sequence (like a list, tuple, dictionary, set, or string).
for i in range(5): # Looping through a range of numbers
print(i)
while
loop: Repeats as long as a certain boolean condition is met.
count = 0
while count < 5:
print(count)
count += 1
- Loop control statements:
break
exits a loop,continue
skips to the next iteration, andpass
does nothing and is used as a placeholder.
for i in range(10):
if i == 3:
continue # Skip the rest of the loop for this iteration
if i == 5:
break # Exit the loop
print(i)
This tutorial covers the basics of lists, tuples, and loops in Python. Experimenting with these concepts will help you understand their usage and functionalities in Python programming.
Python Tutorial: Functions
Functions in Python are blocks of organized, reusable code that perform a specific task. They help to break your program into smaller, modular chunks. As you write more complex programs, functions can help you to reduce repetition and increase clarity.
1. Defining a Function
To define a function in Python, you use the def
keyword followed by the function name and parentheses ()
.
- Syntax:
def function_name(parameters):
"""Docstring (optional)"""
# function body
return result # optional
- Example:
def greet(name):
"""This function greets the person passed in as parameter"""
return f"Hello, {name}!"
2. Calling a Function
To execute a function, you call it by its name followed by parentheses. You can pass arguments to the function inside these parentheses.
- Example:
message = greet("Alice")
print(message) # Output: Hello, Alice!
3. Parameters and Arguments
- Parameters are the variables listed inside the parentheses in the function definition.
- Arguments are the values passed to the function when it is called.
def add(a, b):
return a + b
result = add(3, 5) # 3 and 5 are arguments
print(result) # Output: 8
4. Default Parameter Values
You can define a function with default parameter values, which will be used if no arguments are provided for those parameters.
def print_info(name, age=35):
print(f"Name: {name}, Age: {age}")
print_info("Bob", 50) # Output: Name: Bob, Age: 50
print_info("Bob") # Output: Name: Bob, Age: 35
5. Return Values
The return
statement is used to exit a function and pass back a value to where the function was called.
def square(number):
return number * number
print(square(4)) # Output: 16
6. Variable Scope
Variables defined inside a function are local to that function and cannot be accessed outside of it. However, a function can access variables defined in the scope in which it is called.
def my_function():
local_variable = "local"
print(local_variable)
my_function()
# print(local_variable) # This would raise an error because local_variable is not accessible here
7. Lambda Functions
Lambda functions are small, anonymous functions that can have any number of arguments but only one expression. They are often used for short, simple functions.
multiply = lambda a, b: a * b
print(multiply(5, 6)) # Output: 30
8. Docstrings
Docstrings (documentation strings) are string literals that appear right after the definition of a function, method, class, or module. They are used to document the functionality of the component.
def my_function():
"""This is a docstring. It explains what the function does."""
pass
Using functions effectively can make your code more readable, maintainable, and testable. They allow you to write reusable code and organize your program into modular components.
Python Tutorial: Understanding Mutability
In Python, mutability refers to the ability of an object to be changed after it is created. Understanding mutability is crucial as it affects how objects like lists, tuples, and dictionaries behave in your code.
1. Mutable Objects
Mutable objects can be changed after they are created. Common mutable object types in Python include lists, dictionaries, and sets.
- Lists:
Lists are mutable, meaning you can modify them by adding, removing, or changing their elements.
my_list = [1, 2, 3]
my_list.append(4) # Adding an element
my_list[1] = 'a' # Changing an element
print(my_list) # Output: [1, 'a', 3, 4]
- Dictionaries:
Dictionaries are key-value pairs that are mutable. You can add, remove, or modify the pairs.
my_dict = {'name': 'Alice', 'age': 25}
my_dict['age'] = 26 # Modifying an entry
my_dict['city'] = 'New York' # Adding a new entry
print(my_dict) # Output: {'name': 'Alice', 'age': 26, 'city': 'New York'}
- Sets:
Sets are mutable and can have elements added or removed.
my_set = {1, 2, 3}
my_set.add(4)
my_set.remove(2)
print(my_set) # Output: {1, 3, 4}
2. Immutable Objects
Immutable objects cannot be changed once they are created. Numbers, strings, and tuples are examples of immutable objects in Python.
- Numbers and Strings:
When you change the value of a number or string, a new object is created.
a = 5
a = a + 1 # This doesn't change the value of 5; it creates a new object with the value 6
s = "hello"
s = s + " world" # Creates a new string and assigns it to s
- Tuples:
Tuples are like lists, but they are immutable. You cannot add, remove, or modify elements after the tuple is created.
my_tuple = (1, 2, 3)
# my_tuple[1] = 'a' # This would raise an error
3. Implications of Mutability
- Memory Efficiency: Immutable objects can be more memory efficient because they allow Python to make optimizations under the hood.
- Thread Safety: Immutable objects are inherently thread-safe, as they cannot be modified concurrently by multiple threads.
- Function Arguments: Passing mutable objects as function arguments can lead to unexpected changes if the function modifies the object.
4. Copying Objects
Understanding mutability is crucial when copying objects:
- Shallow Copy: Creates a new compound object but inserts references to the original objects. Use
copy()
for lists.
original = [1, 2, [3, 4]]
shallow_copy = original.copy()
shallow_copy[2].append(5)
print(original) # Output: [1, 2, [3, 4, 5]]
- Deep Copy: Creates a new compound object and recursively inserts copies into it, used for nested objects. Import
deepcopy
from thecopy
module.
import copy
deep_copy = copy.deepcopy(original)
deep_copy[2].append(6)
print(original) # Output remains unchanged: [1, 2, [3, 4, 5]]
In conclusion, understanding mutability in Python helps in managing how objects are stored and manipulated in memory, affecting the behavior and efficiency of your code.
Python Tutorial: Error Handling
Error handling is a crucial aspect of writing robust Python programs. It allows you to anticipate potential errors, handle them gracefully, and maintain the flow of your program. Python provides several mechanisms for dealing with errors, primarily through the use of exceptions.
1. Basic Exception Handling
An exception in Python is an event that disrupts the normal flow of a program. The basic syntax for handling exceptions uses try
and except
blocks.
try
block: Wrap the code that might generate an exception in atry
block.except
block: Handle the exception in anexcept
block.
try:
result = 10 / 0
except ZeroDivisionError:
print("You can't divide by zero!")
In this example, attempting to divide by zero raises a ZeroDivisionError
, which is then caught and handled by the except
block.
2. Catching Multiple Exceptions
You can handle different exceptions in separate except
blocks. This is useful for responding to different exceptions in different ways.
try:
a = int(input("Enter a number: "))
result = 10 / a
except ZeroDivisionError:
print("Division by zero is not allowed.")
except ValueError:
print("Invalid input: please enter a valid integer.")
3. Generic Exception Handling
Using except
without specifying an exception type catches all exceptions. This should be used sparingly, as it can catch unexpected errors and hide programming mistakes.
try:
# risky code
except:
print("An error occurred.")
4. The else
Block
An else
block can be used after except
blocks to execute code only if no exceptions were raised in the try
block.
try:
print("Trying to divide...")
result = 10 / 2
except ZeroDivisionError:
print("Divided by zero!")
else:
print("Division successful!")
5. The finally
Block
The finally
block executes after all the other blocks, regardless of whether an exception was caught or not. It’s typically used for clean-up actions, like closing files or releasing resources.
try:
file = open("example.txt")
# read and process the file
except FileNotFoundError:
print("File not found.")
finally:
file.close()
print("File closed.")
6. Raising Exceptions
You can raise exceptions using the raise
keyword, either re-raising caught exceptions or throwing new ones.
try:
x = int(input("Enter a positive number: "))
if x <= 0:
raise ValueError("That is not a positive number!")
except ValueError as e:
print(e)
7. Custom Exceptions
For specific cases, you can define your own exception classes by inheriting from the Exception
class.
class MyError(Exception):
pass
try:
raise MyError("Something went wrong!")
except MyError as e:
print(e)
In conclusion, effective error handling in Python is essential for building robust and reliable applications. By anticipating and managing potential errors, you can ensure that your program behaves predictably and provides a better user experience.