In Python, the import statement is how you bring code from external modules or packages into your current script. It keeps your code organized, reusable, and efficient.
Depending on what you need and how you want to reference it, there are a few ways to write an import statement:
Imports the entire module. To use anything inside it, you must prefix it with the module name.
import math
# Usage: module_name.function_name()
print(math.sqrt(16)) # Outputs: 4.0
Imports only specific functions, classes, or variables directly into your file. You don't need the module prefix anymore.
from math import sqrt, pi
# Usage: direct access
print(sqrt(25)) # Outputs: 5.0
print(pi) # Outputs: 3.141592653589793
Useful for shortening long module names or avoiding naming conflicts with your own variables/functions.
import pandas as pd
from datetime import datetime as dt
# Usage: using the alias
df = pd.DataFrame()
now = dt.now()
Imports everything from a module.
Warning: This is generally discouraged because it clutters your namespace, makes it hard to tell where functions came from, and can accidentally overwrite existing functions.
from math import *
print(sin(0)) # Works, but it's unclear where 'sin' came from at a glance
When you execute import abc, Python doesn't look everywhere on your computer. It looks in a specific sequence of locations defined in sys.path:
The Current Directory: The folder where your running script is located.
PYTHONPATH: An environment variable you can set with custom directory paths.
Standard Library Directories: The built-in modules that come pre-installed with Python (like math, os, sys).
Site-Packages (Third-Party): Where packages installed via pip (like requests or numpy) live.
Pro Tip: Never name your own Python files the same as a standard library module. If you create a file named math.py and try to import math, Python will import your file instead of the built-in math module, causing errors!
Put them at the top: All import statements should be placed at the very top of your Python file, right after any module comments or docstrings.
Group your imports: Group them in the following order, with a blank line separating each group:
Standard library imports (e.g., import os, import sys)
Related third-party library imports (e.g., import numpy, import requests)
Local application/specific imports (your own modules)
One per line (usually): * Good: import os and import sys on separate lines.
Okay for from: from math import sqrt, ceil is perfectly fine.
A file is a container in computer storage devices used for storing data. When we want to read from or write to a file, we need to open it first. When we are done, it needs to be closed so that the resources that are tied with the file are freed.
Hence, in Python, a file operation takes place in the following order:
Open a file
Read or write (perform operation)
Close the file
When you open a file, it consumes system resources. If you don't close it, you risk data loss or file corruption.
You have to manually close the file, which can fail if an error occurs mid-script.
file = open("example.txt", "r")
content = file.read()
file.close() # Easy to forget!
The with statement creates a context manager. It guarantees that the file will automatically close the moment the code block finishes, even if an error pops up.
with open("example.txt", "r") as file:
content = file.read()
# File is automatically closed here!
The second argument in open(filename, mode) defines what you plan to do with the file:
Depending on how large your file is, you have a few options:
with open("notes.txt", "r") as file:
# Option 1: Read the entire file as a single string
all_data = file.read()
# Option 2: Read line by line (Best for large files to save memory)
for line in file:
print(line.strip()) # .strip() removes newline characters (\n)
# Option 3: Read all lines into a Python list
# lines_list = file.readlines()
Use "w" to fresh-start a file.
Use "a" to keep what's there and add more.
# Overwriting/Creating a file
with open("output.txt", "w") as file:
file.write("Hello, World!\n")
file.write("This will overwrite anything previously in this file.")
# Appending to the same file
with open("output.txt", "a") as file:
file.write("\nThis line is safely added to the end!")
Hardcoding paths like "C:\\users\\documents\\file.txt" can break if your code runs on a different operating system (like Mac or Linux). Instead, use Python's built-in pathlib module.
from pathlib import Path
# Create a path object (handles slashes automatically for Windows/Mac/Linux)
data_folder = Path("current_project/data")
file_path = data_folder / "results.txt"
# You can use pathlib objects directly inside open()
with open(file_path, "w") as file:
file.write("Pathlib makes file handling cross-platform!")
Quick Tip: Before opening a file you aren't sure exists, you can quickly check it using Path("file.txt").exists(), which returns True or False.
Regular Expressions (often shortened to Regex or RegEx) are essentially powerful search-and-replace patterns. Think of it as a supercharged "Ctrl + F" that allows you to search for complex patterns in text rather than just exact words.
Whether you are validating an email address, scraping data from the web, or cleaning up a messy dataset, regex is the ultimate tool for the job.
Regex uses a combination of literal characters (like the letters abc) and metacharacters (special symbols that represent rules). Here is a cheat sheet of the most common components:
These tell regex what kind of character you are looking for.
. (Dot) – Matches any single character except a new line.
\d – Matches any digit (0-9).
\w – Matches any word character (letters, numbers, and underscores).
\s – Matches any whitespace (spaces, tabs, line breaks).
[abc] – Matches any one of the characters inside the brackets (a, b, or c).
[^abc] – Matches any character not inside the brackets.
\b – matches a word boundary
\W – matches a special character
These tell regex how many times the previous character or group should repeat.
* – 0 or more times.
+ – 1 or more times.
? – 0 or 1 time (makes it optional).
{n} – Exactly n times.
{n,m} – Between n and m times.
These don't match actual characters; instead, they lock the pattern to a specific position.
^ – Matches the start of a line.
$ – Matches the end of a line.
Imagine you want to find U.S. phone numbers in the format 123-456-7890.
The Regex: \d{3}-\d{3}-\d{4}
How it works: * \d{3} looks for exactly 3 digits.
- looks for a literal hyphen.
\d{3} looks for another 3 digits.
- looks for another hyphen.
\d{4} looks for exactly 4 digits.
An email usually looks like username@domain.com.
The Regex: [\w.-]+@[\w.-]+\.[a-zA-Z]{2,}
How it works:
[\w.-]+ matches one or more letters, numbers, dots, or hyphens (the username).
@ matches the literal "@" symbol.
[\w.-]+ matches the domain name.
\. matches a literal dot (we use the backslash \ to "escape" it, otherwise the dot means "any character").
[a-zA-Z]{2,} matches a top-level domain (like .com, .org, .edu) that is at least 2 letters long.
If you are processing logs or databases, you often need to find or validate date formats.
The Regex: ^\d{4}-\d{2}-\d{2}$
How it works:
^ asserts the start of the string (ensures no extra text comes before the date).
\d{4} matches exactly 4 digits for the year (e.g., 2026).
- matches the literal hyphen separator.
\d{2} matches exactly 2 digits for the month (e.g., 06).
- matches the second hyphen separator.
\d{2} matches exactly 2 digits for the day (e.g., 22).
$ asserts the end of the string (ensures no extra text comes after the date).
Matches: 2026-06-22
Non-Match: 26-06-22 or 2026-6-22
Many systems use regex to ensure a password meets basic security requirements. Let's build a pattern that requires at least one uppercase letter, one lowercase letter, one number, and a minimum of 8 characters.
The Regex: ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*\W).{8,}$
This regex is a password strength validator that checks the input string from start to finish (^ and $). It uses "lookaheads" (?=...) to act as a checklist without moving the search position forward.
Here is the 5-point checklist it enforces:
(?=.*[a-z]) → Must contain at least one lowercase letter.
(?=.*[A-Z]) → Must contain at least one uppercase letter.
(?=.*\d) → Must contain at least one digit (0-9).
(?=.*\W) → Must contain at least one special character (like !, @, #).
.{8,} → Total length must be 8 or more characters.
If the password ticks all 5 boxes, it's a match!
If you are analyzing web traffic data, you might want to extract tracking IDs or search queries from a URL. Imagine you want to find the word after ?q= in a URL like https://example.com/search?q=regex_tutorial.
The Regex: \?q=([^&]+)
How it works (Using Capture Groups):
\?q= matches the literal string ?q= (the question mark is escaped).
(...) Parentheses create a capture group. This tells your programming language, "Hey, remember exactly what matched inside here so I can extract it later."
[^&]+ matches one or more characters that are not an ampersand (&). This ensures the match stops if there are more parameters attached to the URL (like &lang=en).
Matches: Extracts regex_tutorial from .../search?q=regex_tutorial&lang=en.
When scraping data from a website, you often get raw HTML back but only want the plain text inside.
The Regex: <[^>]+>
How it works:
< matches the opening angle bracket of an HTML tag.
[^>]+ matches one or more characters that are not a closing angle bracket.
> matches the closing angle bracket.
Usage: If you use a search-and-replace tool and replace this pattern with an empty string, <h1>Welcome</h1> becomes just Welcome.
Example 7: Word Boundary
Imagine you are cleaning up a text document and want to replace or highlight the standalone word "plan", but you want to completely ignore words that just contain those letters, like "planet", "plantation", or "unplanned".
Your Text:
"We need a solid plan before we explore the planet or start a new plantation."
If you just search for plan, the regex engine grabs every instance where those four letters appear in a row.
Matches: "We need a solid plan..."
Matches: "...explore the planet..."
Matches: "...or start a new plantation."
By placing \b on both sides, you force the engine to check if the surrounding characters are non-word characters (like spaces or punctuation).
\b (Left): Is the character before 'p' a space? Yes.
\b (Right): Is the character after 'n' a space or period? Yes.
Result: It matches only the standalone word:
"We need a solid plan before we explore the planet or start a new plantation."
RegEx Module in Python
Python has a built-in package called re, which can be used to work with Regular Expressions. A Python regular expression is a sequence of metacharacters that define a search pattern. We use these patterns in a string-searching algorithm to "find" or "find and replace" on strings. The term "regular expressions" is frequently shortened to "RegEx".
findall() function
The findall() function returns a list containing all matches.
Example:
import re
text = "The Galeb class were minelayers originally built as \
minesweepers for the Imperial German Navy between 1918 and 1919.\
They were also known as the Orao class."
# Find out the number of words which contain the letter a
found=re.findall("a",text)
print(len(found))
# Output: 13
# Find out the number of times the word "as" is repeated in the sentence
# We define the word we are searching for within a boundary
# We also define the regular expression as a raw string
found=re.findall(r"\b(as)\b",text)
print(len(found))
# Output: 2
split() function
The split() function returns a list that shows where the string has been split at each match.
Example:
import re
text = "The Galeb class were minelayers originally built as \
minesweepers for the Imperial German Navy between 1918 and 1919.\
They were also known as the Orao class."
# Split the string into an array of elements
split_str=re.split(r"\s",text)
print(split_str)
"""
Output:
['The', 'Galeb', 'class', 'were', 'minelayers', 'originally',
'built', 'as', 'minesweepers', 'for', 'the', 'Imperial', 'German',
'Navy', 'between', '1918', 'and', '1919.They', 'were', 'also', 'known',
'as', 'the', 'Orao', 'class.']
"""
search() function
The search() function takes a regular expression pattern and a string, and it searches for that pattern within the string. If the search is successful, search() returns a match object. Otherwise, it doesn’t return any.
In Python's re module, match() and search() return match objects when a string matches a regular expression pattern. You can extract the matched string and its position using methods provided by the match object. re. match() searches for matches from the beginning of a string while re.search() searches for matches anywhere in the string.
Example:
import re
text = "The Galeb class were minelayers originally built as \
minesweepers for the Imperial German Navy between 1918 and 1919.\
They were also known as the Orao class."
# Find the first position of the word class
index=re.search("class",text)
print("The word is located at position:",index.start())
# Output: The word is located at position: 10
sub() Function
The sub() function replaces the matches with the text of your choice:
Example:
import re
text="Eric is an IT Graduate. Eric is a specialist in Cloud Computing."
text=re.sub("Eric","Aaron",text)
print(text)
# Output: Aaron is an IT Graduate. Aaron is a specialist in Cloud Computing.
text=re.sub(r"\b\w{3,5}\b","Grid",text)
print(text)
# Output: Grid is an IT Graduate. Grid is a specialist in Grid Computing.
Get the matched position: start(), end(), span()
You can get the position (index) of the matched substring using the match object's methods start(), end(), and span().
Example:
import re
text="Eric is an IT Graduate. Eric is a specialist in Cloud Computing."
matched=re.search(r"\b(IT)\b",text)
print(matched.start())
print(matched.end())
print(matched.span())
# Output:
# 11
# 13
# (11,13)
Group Extraction
The "group" feature of a regular expression allows you to pick out parts of the matching text.
Suppose for the emails problem that we want to extract the username and host separately. To do this, add parentheses ( ) around the username and host in the pattern, like this: r'([\w.-]+)@([\w.-]+)'. In this case, the parentheses do not change what the pattern will match, instead they establish logical "groups" inside of the match text. On a successful search, match.group(1) is the match text corresponding to the 1st left parentheses, and match.group(2) is the text corresponding to the 2nd left parentheses. The plain match.group() is still the whole match text as usual.
Examples:
# Example 1:
text="Contact us at support@test.com"
em=re.search(r"([\w.-]+)@([\w.-]+)",text)
if em:
print(em.group())
print(em.group(1))
print(em.group(2))
print(em.groups())
# Output:
# support@test.com
# support
# test.com
# ('support', 'test.com')
# Example 2: Extract the usernames from multiple emails
text="Contact us at support@test.com or at products@test.com"
em=re.findall(r"([\w.-]+)@([\w.-]+)",text)
print(em)
# Output: [('support', 'test.com'), ('products', 'test.com')]
for e in em:
print(e[0])
# Output:
# support
# products