- What are docstrings — documentation strings that explain your code
- Why write them — make code self-documenting, help others
- Basic docstrings — one-line and multi-line
- Docstring formats — Google, NumPy, and Sphinx styles
- Docstrings for classes — documenting classes and methods
- Real-world use — practical examples
What are Docstrings?
A docstring (documentation string) is a string literal that appears as the first statement in a module, function, class, or method definition. It's used to document what the code does.
Think of docstrings like labels on a filing cabinet. Without labels, you'd have to open every drawer to find what you need. With labels, you know exactly where everything is. Docstrings work the same way — they tell you what code does without having to read the code itself.
Docstrings are different from comments. Comments are for developers reading the code. Docstrings are for users who want to know how to use the code.
💡 Key concept: Docstrings are the first string in a function, class, or module. They're used to document what the code does and are accessible via help() and .__doc__.
Why Write Docstrings?
The Benefits of Docstrings
Writing docstrings is a best practice that makes your code better in many ways.
# Why Write Docstrings?
print("=" * 50)
print("WHY WRITE DOCSTRINGS?")
print("=" * 50)
# ============================================================
# WITHOUT DOCSTRINGS - Hard to Understand
# ============================================================
print("\n1. WITHOUT DOCSTRINGS")
print("""
def process_data(items, factor):
result = []
for item in items:
result.append(item * factor)
return result
# What does this function do?
# What are the parameters?
# What does it return?
# We have to read the code to find out!
""")
# ============================================================
# WITH DOCSTRINGS - Clear and Self-Documenting
# ============================================================
print("\n2. WITH DOCSTRINGS")
print("""
def process_data(items, factor):
\"\"\"Multiply every item in a list by a factor.
Args:
items (list): A list of numbers.
factor (float): The number to multiply each item by.
Returns:
list: A new list with each item multiplied by the factor.
Example:
>>> process_data([1, 2, 3], 2)
[2, 4, 6]
\"\"\"
result = []
for item in items:
result.append(item * factor)
return result
# Everything is clear!
""")
# ============================================================
# USING HELP() WITH DOCSTRINGS
# ============================================================
print("\n3. USING help()")
print("""
def calculate_average(numbers):
\"\"\"Calculate the average of a list of numbers.\"\"\"
if not numbers:
return 0
return sum(numbers) / len(numbers)
# help(calculate_average) shows:
# Help on function calculate_average in module __main__:
#
# calculate_average(numbers)
# Calculate the average of a list of numbers.
""")
# ============================================================
# BENEFITS SUMMARY
# ============================================================
print("\n" + "-" * 30)
print("BENEFITS OF DOCSTRINGS")
print("-" * 30)
print("""
- Code is self-documenting
- Users can use help() to learn about your code
- IDE integration (autocomplete, tooltips)
- Generate documentation automatically (Sphinx)
- Easier to maintain and update
- Better collaboration with team members
- Shows professionalism
""")
Benefits of docstrings:
- Self-documenting — code explains itself
- help() — users can get documentation
- IDE support — tooltips and autocomplete
- Auto-generation — create documentation with Sphinx
- Maintainability — easier to update and understand
Quick Check: What function shows a function's docstring? (Answer: help() or print(func.__doc__))
Basic Docstrings
One-Line and Multi-Line Docstrings
Docstrings can be one line or multiple lines. Both are useful in different situations.
# Basic Docstrings
print("=" * 50)
print("BASIC DOCSTRINGS")
print("=" * 50)
# ============================================================
# ONE-LINE DOCSTRING
# ============================================================
print("\n1. ONE-LINE DOCSTRING")
print("""
def add(a, b):
\"\"\"Add two numbers and return the result.\"\"\"
return a + b
# One-line docstrings are for simple functions
# Keep them short and descriptive
""")
def add(a, b):
"""Add two numbers and return the result."""
return a + b
print(f" add.__doc__: {add.__doc__}")
# ============================================================
# MULTI-LINE DOCSTRING
# ============================================================
print("\n2. MULTI-LINE DOCSTRING")
print("""
def calculate_area(shape, dimensions):
\"\"\"Calculate the area of different shapes.
Supports:
- Rectangle: dimensions = (width, height)
- Circle: dimensions = (radius,)
- Triangle: dimensions = (base, height)
Args:
shape (str): The type of shape ('rectangle', 'circle', 'triangle')
dimensions (tuple): The dimensions needed for the shape
Returns:
float: The calculated area
Raises:
ValueError: If the shape is not supported
\"\"\"
pass
""")
# ============================================================
# ACCESSING DOCSTRINGS
# ============================================================
print("\n3. ACCESSING DOCSTRINGS")
def multiply(a, b):
"""Multiply two numbers and return the result."""
return a * b
# Using __doc__
print(f" multiply.__doc__: {multiply.__doc__}")
# Using help() (in interactive mode)
print(" help(multiply) - shows the docstring in the console")
# ============================================================
# DOCSTRING RULES
# ============================================================
print("\n4. DOCSTRING RULES")
print("""
┌─────────────────────────────────────────────────────────────────────┐
│ RULES │
├─────────────────────────────────────────────────────────────────────┤
│ 1. The docstring must be the first statement in the function/class │
│ 2. Use triple quotes (''' or \"\"\") │
│ 3. One-line: keep it on one line │
│ 4. Multi-line: summary line, blank line, then details │
│ 5. First line should be a short summary │
│ 6. End with a period. │
└─────────────────────────────────────────────────────────────────────┘
""")
Basic docstrings key points:
- Triple quotes — use
'''or""" - First statement — must be the first thing in the function/class
- One-line — short description on one line
- Multi-line — summary, blank line, details
- Access — use
.__doc__orhelp()
Quick Check: What delimiters are used for docstrings? (Answer: Triple quotes ''' or """)
Docstring Formats
Google, NumPy, and Sphinx Styles
There are several popular docstring formats. Choose one and be consistent.
# Docstring Formats
print("=" * 50)
print("DOCSTRING FORMATS")
print("=" * 50)
# ============================================================
# 1. GOOGLE STYLE (Most Popular)
# ============================================================
print("\n1. GOOGLE STYLE")
print("""
def process_user(name, age, email=None):
\"\"\"Process user data and return a user object.
Args:
name (str): The user's full name.
age (int): The user's age in years.
email (str, optional): The user's email address.
Returns:
dict: A dictionary with user information.
Raises:
ValueError: If age is less than 0.
Example:
>>> user = process_user("Alice", 30, "alice@example.com")
>>> print(user['name'])
Alice
\"\"\"
pass
""")
# ============================================================
# 2. NUMPY STYLE (Common in Data Science)
# ============================================================
print("\n2. NUMPY STYLE")
print("""
def calculate_stats(data):
\"\"\"Calculate statistical measures for the data.
Parameters
----------
data : list or array-like
The input data to analyze.
axis : int, optional
The axis to calculate along (default is None).
Returns
-------
mean : float
The mean of the data.
std : float
The standard deviation.
Examples
--------
>>> calculate_stats([1, 2, 3, 4, 5])
(3.0, 1.58)
\"\"\"
pass
""")
# ============================================================
# 3. SPHINX STYLE (Good for Documentation Generation)
# ============================================================
print("\n3. SPHINX STYLE")
print("""
def connect_database(host, port, user, password):
\"\"\"Connect to a database server.
:param host: The database server hostname.
:type host: str
:param port: The database server port.
:type port: int
:param user: The username for authentication.
:type user: str
:param password: The password for authentication.
:type password: str
:returns: A database connection object.
:rtype: DatabaseConnection
:raises ConnectionError: If the connection fails.
\"\"\"
pass
""")
# ============================================================
# 4. FORMAT COMPARISON
# ============================================================
print("\n4. FORMAT COMPARISON")
print("""
┌─────────────────────────────┬─────────────────────────────────────────────┐
│ FORMAT │ BEST FOR │
├─────────────────────────────┼─────────────────────────────────────────────┤
│ Google Style │ General purpose (most popular) │
│ NumPy Style │ Data science, scientific computing │
│ Sphinx Style │ Generating documentation with Sphinx │
├─────────────────────────────┼─────────────────────────────────────────────┤
│ │ │
│ Choose one format and stick with it! │
│ Google Style is recommended for most projects. │
└─────────────────────────────────────────────────────────────────────────┘
""")
Docstring formats key points:
- Google Style — most popular, easy to read
- NumPy Style — common in data science
- Sphinx Style — for documentation generation
- Be consistent — choose one format and stick with it
Quick Check: What is the most popular docstring format? (Answer: Google Style)
Docstrings for Classes
Documenting Classes and Methods
Classes should have docstrings that explain what the class does and how to use it.
# Docstrings for Classes
print("=" * 50)
print("DOCSTRINGS FOR CLASSES")
print("=" * 50)
# ============================================================
# CLASS WITH DOCSTRINGS
# ============================================================
print("\n1. CLASS WITH DOCSTRINGS")
print("""
class BankAccount:
\"\"\"A simple bank account that handles deposits and withdrawals.
This class provides basic banking operations including:
- Depositing money
- Withdrawing money
- Checking balance
Attributes:
owner (str): The name of the account owner.
balance (float): The current account balance.
Example:
>>> account = BankAccount("Alice", 1000)
>>> account.deposit(500)
1500.0
>>> account.withdraw(200)
1300.0
\"\"\"
def __init__(self, owner, initial_balance=0):
\"\"\"Initialize the bank account.
Args:
owner (str): The name of the account owner.
initial_balance (float, optional): Starting balance. Defaults to 0.
\"\"\"
self.owner = owner
self.balance = initial_balance
def deposit(self, amount):
\"\"\"Deposit money into the account.
Args:
amount (float): The amount to deposit.
Returns:
float: The new balance.
Raises:
ValueError: If the deposit amount is negative.
\"\"\"
if amount < 0:
raise ValueError("Deposit amount must be positive")
self.balance += amount
return self.balance
def withdraw(self, amount):
\"\"\"Withdraw money from the account.
Args:
amount (float): The amount to withdraw.
Returns:
float: The new balance.
Raises:
ValueError: If the withdrawal amount is invalid.
\"\"\"
if amount < 0:
raise ValueError("Withdrawal amount must be positive")
if amount > self.balance:
raise ValueError("Insufficient funds")
self.balance -= amount
return self.balance
""")
# ============================================================
# DOCSTRING FOR CLASS ATTRIBUTES
# ============================================================
print("\n2. DOCSTRING FOR CLASS ATTRIBUTES")
print("""
class Product:
\"\"\"A product in the inventory system.
Attributes:
name (str): The product name.
price (float): The product price.
quantity (int): The number of items in stock.
category (str): The product category.
\"\"\"
def __init__(self, name, price, quantity, category="General"):
self.name = name
self.price = price
self.quantity = quantity
self.category = category
@property
def total_value(self):
\"\"\"Calculate the total value of this product in stock.
Returns:
float: The total value (price * quantity).
\"\"\"
return self.price * self.quantity
""")
Class docstrings key points:
- Class docstring — explains what the class does
- Method docstrings — explain each method
- Attributes — document what attributes the class has
- Example — include an example of how to use the class
Quick Check: Where does a class docstring go? (Answer: Right after the class definition, before any methods)
Real-World Example
Building a Well-Documented Module
# Real-World Example: Well-Documented Module
print("=" * 60)
print("WELL-DOCUMENTED MODULE")
print("=" * 60)
# ============================================================
# A COMPLETE MODULE WITH DOCSTRINGS
# ============================================================
print("\n1. MODULE DOCSTRING")
print("""
\"\"\"
String Utilities Module
A collection of utility functions for working with strings.
Provides common string operations like reversing, counting
vowels, and checking for palindromes.
Example:
>>> from string_utils import reverse_string, is_palindrome
>>> reverse_string("hello")
'olleh'
>>> is_palindrome("racecar")
True
\"\"\"
""")
# ============================================================
# FUNCTION WITH COMPLETE DOCUMENTATION
# ============================================================
print("\n2. FUNCTION DOCUMENTATION")
print("""
def count_vowels(text):
\"\"\"Count the number of vowels in a string.
Counts both lowercase and uppercase vowels (a, e, i, o, u).
Args:
text (str): The string to analyze.
Returns:
int: The number of vowels in the text.
Example:
>>> count_vowels("Hello World!")
3 # e, o, o
>>> count_vowels("Python")
1 # o
\"\"\"
vowels = "aeiouAEIOU"
return sum(1 for char in text if char in vowels)
def is_palindrome(text):
\"\"\"Check if a string is a palindrome.
A palindrome is a word, phrase, or sequence that reads
the same forward and backward, ignoring case and spaces.
Args:
text (str): The string to check.
Returns:
bool: True if the text is a palindrome, False otherwise.
Example:
>>> is_palindrome("racecar")
True
>>> is_palindrome("A man a plan a canal Panama")
True
>>> is_palindrome("hello")
False
\"\"\"
cleaned = text.lower().replace(" ", "")
return cleaned == cleaned[::-1]
""")
# ============================================================
# CLASS WITH COMPLETE DOCUMENTATION
# ============================================================
print("\n3. CLASS DOCUMENTATION")
print("""
class TextAnalyzer:
\"\"\"A class for analyzing text content.
Provides methods for text analysis including word count,
character frequency, and finding the most common words.
Attributes:
text (str): The text to analyze.
words (list): List of words in the text (cached).
Example:
>>> analyzer = TextAnalyzer("Hello world hello Python")
>>> analyzer.get_word_count()
4
>>> analyzer.get_most_common_words(2)
[('hello', 2), ('python', 1)]
\"\"\"
def __init__(self, text):
\"\"\"Initialize the analyzer with text.
Args:
text (str): The text to analyze.
\"\"\"
self.text = text
self._words = None
def get_word_count(self):
\"\"\"Get the total number of words in the text.
Returns:
int: The number of words.
\"\"\"
return len(self._get_words())
def get_most_common_words(self, n=5):
\"\"\"Get the most common words in the text.
Args:
n (int): The number of top words to return.
Returns:
list: A list of tuples (word, count) in descending order.
\"\"\"
from collections import Counter
words = self._get_words()
return Counter(words).most_common(n)
def _get_words(self):
\"\"\"Internal method to cache and return the list of words.
Returns:
list: The list of words in the text.
\"\"\"
if self._words is None:
self._words = self.text.lower().split()
return self._words
""")
Real-world example key points:
- Module docstring — explains the whole module
- Function docstrings — explain parameters, returns, examples
- Class docstring — explains the class and attributes
- Method docstrings — explain each method
- Internal methods — still documented with
_
Quick Check: What should a module docstring contain? (Answer: A description of what the module does and examples of how to use it)
Best Practices
Writing Great Docstrings
# Best Practices for Docstrings
print("=" * 60)
print("BEST PRACTICES FOR DOCSTRINGS")
print("=" * 60)
# ============================================================
# 1. BE CONSISTENT WITH THE FORMAT
# ============================================================
print("\n1. BE CONSISTENT WITH THE FORMAT")
print("""
# Good - consistent Google Style
def add(a, b):
\"\"\"Add two numbers.
Args:
a (int): First number.
b (int): Second number.
Returns:
int: The sum of a and b.
\"\"\"
return a + b
def multiply(a, b):
\"\"\"Multiply two numbers.
Args:
a (int): First number.
b (int): Second number.
Returns:
int: The product of a and b.
\"\"\"
return a * b
""")
# ============================================================
# 2. BE CONCISE BUT COMPLETE
# ============================================================
print("\n2. BE CONCISE BUT COMPLETE")
print("""
# Good - concise but complete
def get_user(user_id):
\"\"\"Get a user by ID.
Args:
user_id (int): The user's ID.
Returns:
dict: User data if found, None otherwise.
Raises:
ValueError: If user_id is negative.
\"\"\"
pass
# Bad - too much detail
def get_user(user_id):
\"\"\"This function takes a user ID which should be an integer and then it
queries the database to find the user with that ID. If the user is found,
it returns a dictionary with the user's name, email, and other information.
If the user is not found, it returns None. If the user ID is negative,
it raises a ValueError. This is the main function for retrieving users.
\"\"\"
pass
""")
# ============================================================
# 3. INCLUDE EXAMPLES
# ============================================================
print("\n3. INCLUDE EXAMPLES")
print("""
# Good - includes example
def calculate_tax(amount, rate=0.08):
\"\"\"Calculate tax on a given amount.
Args:
amount (float): The pre-tax amount.
rate (float, optional): The tax rate. Defaults to 0.08.
Returns:
float: The tax amount.
Example:
>>> calculate_tax(100)
8.0
>>> calculate_tax(100, 0.1)
10.0
\"\"\"
return amount * rate
""")
# ============================================================
# 4. DOCUMENT EXCEPTIONS
# ============================================================
print("\n4. DOCUMENT EXCEPTIONS")
print("""
def divide(a, b):
\"\"\"Divide two numbers.
Args:
a (float): The numerator.
b (float): The denominator.
Returns:
float: The result of a / b.
Raises:
ZeroDivisionError: If b is 0.
TypeError: If a or b is not a number.
\"\"\"
return a / b
""")
# ============================================================
# 5. UPDATE DOCSTRINGS WITH CODE
# ============================================================
print("\n5. UPDATE DOCSTRINGS WITH CODE")
print("""
# Always update docstrings when you change the code!
# Good - docstring matches the code
def get_user(user_id):
\"\"\"Get a user by ID.\"\"\"
pass
# Bad - docstring doesn't match the code
def get_user(user_id, include_deleted=False):
\"\"\"Get a user by ID.\"\"\" # Doesn't mention include_deleted
pass
""")
# ============================================================
# 6. SUMMARY
# ============================================================
print("\n" + "=" * 60)
print("BEST PRACTICES SUMMARY")
print("=" * 60)
print("""
- Be consistent with your chosen format
- Be concise but include all necessary information
- Include examples when helpful
- Document exceptions and error cases
- Update docstrings when code changes
- Use triple quotes for all docstrings
- First line should be a short summary
- Use type hints alongside docstrings
""")
Best practices summary:
- Be consistent — use the same format throughout
- Be concise — include all needed info, but not too much
- Include examples — show how to use the function
- Document exceptions — mention what errors can occur
- Update with code — keep docstrings current
Quick Check: Should you update docstrings when you change the code? (Answer: Yes, docstrings should always match the code)
Try It Yourself
Practice writing docstrings in the editor below.
DOCSTRINGS - PRACTICE
==================================================
1. FUNCTION WITH DOCSTRING
calculate_discount.__doc__: Calculate the discounted price.
calculate_discount(100, 10): 90.0
2. CLASS WITH DOCSTRINGS
Cart total: $37.98
ShoppingCart.__doc__: A simple shopping cart.
You've Got It!
You now understand docstrings in Python. You know how to write them, what formats to use, and why they're important for self-documenting code.
Quick Quiz
Test what you've learned:
Frequently Asked Questions
What is a docstring in Python?
What's the difference between a comment and a docstring?
What docstring format should I use?
Should I include examples in docstrings?
Can I use type hints instead of documenting types in docstrings?
What tools can generate documentation from docstrings?
Where to Go From Here
Now that you understand docstrings, check out these related topics:
Logging
Learn how to add logging to your applications.
Learn More →Code Optimization
Learn how to write efficient Python code.
Learn More →PEP 8
Learn about Python's style guide.
Learn More →