|

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 or pop() 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, and pass 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 the copy 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 a try block.
  • except block: Handle the exception in an except 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.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *