Intermediate
Why Logging Matters in Python
You’re debugging a production issue, but your application is silent. You added a few print() statements weeks ago, the messages got buried in the terminal, and now you have no idea what’s happening. Or worse: your app is logging to console, but the logs disappear the moment the process restarts. You need a way to capture what your application is doingâwhen it’s doing it, at what severity level, and where it should be recorded.
This is where Python’s built-in logging module becomes essential. Unlike print() statements, which are crude and destructive once you delete them, the logging module is a professional-grade system designed for production applications. It comes built-in to Python, requires no external dependencies, and provides granular control over message levels, formatting, and output destinations.
In this article, you’ll learn how to set up the logging module to output messages simultaneously to both your console (for immediate feedback during development) and to a file (for long-term record-keeping and debugging). We’ll cover logging levels, handlers, formatters, log rotation to prevent massive log files, and the patterns used in real multi-module projects. By the end, you’ll understand how to instrument your code with logging that developers trust.
How To Set Up Logging: Quick Example
Here’s a minimal example that outputs log messages to both console and file:
# quick_logging_example.py
import logging
# Create a logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# File handler
file_handler = logging.FileHandler("app.log")
file_handler.setLevel(logging.DEBUG)
# Console handler
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# Formatter
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)
# Add handlers to logger
logger.addHandler(file_handler)
logger.addHandler(console_handler)
# Log some messages
logger.debug("Debug message (goes to file only)")
logger.info("Info message (goes to both)")
logger.warning("Warning message (goes to both)")
logger.error("Error message (goes to both)")
logger.critical("Critical message (goes to both)")
Output (to console):
2026-03-29 14:22:15,342 - __main__ - INFO - Info message (goes to both)
2026-03-29 14:22:15,343 - __main__ - WARNING - Warning message (goes to both)
2026-03-29 14:22:15,344 - __main__ - ERROR - Error message (goes to both)
2026-03-29 14:22:15,344 - __main__ - CRITICAL - Critical message (goes to both)
Output (written to app.log):
2026-03-29 14:22:15,341 - __main__ - DEBUG - Debug message (goes to file only)
2026-03-29 14:22:15,342 - __main__ - INFO - Info message (goes to both)
2026-03-29 14:22:15,343 - __main__ - WARNING - Warning message (goes to both)
2026-03-29 14:22:15,344 - __main__ - ERROR - Error message (goes to both)
2026-03-29 14:22:15,344 - __main__ - CRITICAL - Critical message (goes to both)
Notice the key pattern: we created a logger, attached two separate handlers (one for files, one for console), set different levels for each, and applied a formatter that includes timestamps and severity levels. This is the foundation for everything that follows. The sections below show you how to customize each piece.
What is Python Logging and Why Use It?
The logging module is Python’s standard library tool for recording events that happen during program execution. Unlike print statements, logging provides:
- Severity levels â categorize messages by importance (DEBUG, INFO, WARNING, ERROR, CRITICAL)
- Multiple outputs â send logs to files, console, email, syslog, or custom handlers simultaneously
- Formatting control â include timestamps, function names, line numbers, and custom metadata
- Filtering â selectively log messages based on logger name, level, or custom criteria
- No side effects â unlike print, you can leave logging code in production without cluttering output
The alternativeâusing print() for debuggingâbreaks down immediately:
| Aspect | print() Statements | logging Module |
|---|---|---|
| Disable in production | Must manually remove | Adjust level, keep code in place |
| Output destination | Always stdout | File, console, email, or custom |
| Timestamps | Manual string concatenation | Automatic, customizable format |
| Severity levels | None | DEBUG, INFO, WARNING, ERROR, CRITICAL |
| Performance | Always evaluates | Can be filtered; lazy evaluation |
| Multi-module coordination | No built-in support | Hierarchical logger names |
The logging module is designed for exactly what you need: professional-grade event recording that stays in your code indefinitely.
Understanding Logging Levels
Python’s logging module defines five standard severity levels, plus a catch-all NOTSET. Each level has a numeric value, and loggers will only record messages at or above their configured level:
| Level | Numeric Value | When to Use | Example |
|---|---|---|---|
| DEBUG | 10 | Detailed diagnostic info for debugging | Variable values, function entry/exit, loop iterations |
| INFO | 20 | General informational messages | Application startup, config loaded, request received |
| WARNING | 30 | Something unexpected or potentially harmful | Deprecated API usage, missing optional config, retrying failed request |
| ERROR | 40 | A serious problem; some operation failed | File not found, API returned 500, database connection lost |
| CRITICAL | 50 | A very serious error; program may not continue | Out of memory, permissions denied, unrecoverable system error |
When you set a logger’s level to INFO, it will log INFO, WARNING, ERROR, and CRITICAL messagesâbut not DEBUG messages. This is how you control verbosity.
# logging_levels_demo.py
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# Add a console handler so we can see output
handler = logging.StreamHandler()
handler.setLevel(logging.WARNING)
formatter = logging.Formatter("%(levelname)s - %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
# These will NOT appear (level is below WARNING)
logger.debug("This is a debug message")
logger.info("This is an info message")
# These WILL appear
logger.warning("This is a warning message")
logger.error("This is an error message")
logger.critical("This is a critical message")
Output:
WARNING - This is a warning message
ERROR - This is an error message
CRITICAL - This is a critical message
Notice: the logger itself has one level (DEBUG), but the console handler has a different level (WARNING). You can filter messages at multiple levelsâfirst at the logger, then at each handler. This is crucial for sending different messages to different outputs (e.g., all DEBUG messages to a debug log file, only ERROR+ to a critical alert file).
Handlers and Formatters: Controlling Where and How Logs Go
A logger is just a container. The actual work happens in handlers and formatters:
- Handler â an output destination.
FileHandlerwrites to a file,StreamHandlerwrites to console, etc. - Formatter â defines how log messages are formatted: which fields to include (timestamp, function name, etc.) and in what order
You create a handler, assign a formatter to it, set a level, and attach it to a logger. A single logger can have multiple handlers, each with different levels and formatters.
Creating a StreamHandler (Console Output):
# stream_handler_example.py
import logging
logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)
# Create a console handler
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# Format: timestamp, logger name, level, message
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
logger.info("Application started")
logger.warning("This is a warning")
logger.error("An error occurred")
Output:
2026-03-29 14:25:30,123 - myapp - INFO - Application started
2026-03-29 14:25:30,124 - myapp - WARNING - This is a warning
2026-03-29 14:25:30,125 - myapp - ERROR - An error occurred
The %(asctime)s token automatically includes a timestamp. Other useful tokens include %(funcName)s (the function name), %(lineno)d (line number), and %(module)s (the module filename).
Creating a FileHandler (File Output):
# file_handler_example.py
import logging
logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)
# Create a file handler
file_handler = logging.FileHandler("app.log")
file_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.debug("Debug: application starting")
logger.info("Info: loading configuration")
logger.warning("Warning: deprecated API used")
logger.error("Error: failed to connect to database")
After running this, check your app.log file. All four messages will be there because the file handler’s level is DEBUG.
Output (written to app.log):
2026-03-29 14:27:01,456 - myapp - DEBUG - Debug: application starting
2026-03-29 14:27:01,457 - myapp - INFO - Info: loading configuration
2026-03-29 14:27:01,458 - myapp - WARNING - Warning: deprecated API used
2026-03-29 14:27:01,459 - myapp - ERROR - Error: failed to connect to database
Logging to Console and File Simultaneously
The most common pattern in production is to send all logs to a file (for permanent record) and only show WARNING+ messages on the console (for immediate visibility during operation). Here’s how:
# console_and_file_logging.py
import logging
import os
# Create a logger
logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)
# Create log directory if it doesn't exist
log_dir = "logs"
if not os.path.exists(log_dir):
os.makedirs(log_dir)
# File handler: captures all messages
file_handler = logging.FileHandler(os.path.join(log_dir, "app.log"))
file_handler.setLevel(logging.DEBUG)
# Console handler: shows only warnings and above
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.WARNING)
# Shared formatter for both handlers
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)
# Attach handlers to logger
logger.addHandler(file_handler)
logger.addHandler(console_handler)
# Lof messages at different levels
logger.debug("Starting application initialization")
logger.info("Configuration loaded successfully")
logger.info("Database connection established")
logger.warning("API response time is higher than usual")
logger.error("Failed to write to cache, continuing without cache")
logger.critical("Memory usage exceeded safe threshold")
Output (to console):
2026-03-29 14:30:12 - myapp - WARNING - API response time is higher than usual
2026-03-29 14:30:12 - myapp - ERROR - Failed to write to cache, continuing without cache
2026-03-29 14:30:12 - myapp - CRITICAL - Memory usage exceeded safe threshold
Output (written to logs/app.log):
2026-03-29 14:30:12 - myapp - DEBUG - Starting application initialization
2026-03-29 14:30:12 - myapp - INFO - Configuration loaded successfully
2026-03-29 14:30:12 - myapp - INFO - Database connection established
2026-03-29 14:30:12 - myapp - WARNING - API response time is higher than usual
2026-03-29 14:30:12 - myapp - ERROR - Failed to write to cache, continuing without cache
2026-03-29 14:30:12 - myapp - CRITICAL - Memory usage exceeded safe threshold
This pattern is powerful: you get a permanent record of everything (including debug messages developers need when troubleshooting), but the console stays clean during normal operationâonly showing problems that need immediate attention. When a warning or error occurs, developers see it right away.
Custom Log Formatting with Timestamps and Metadata
The formatter string controls what information appears in each log message. The most useful format tokens are:
| Token | Meaning | Example |
|---|---|---|
%(asctime)s | Timestamp (human-readable) | 2026-03-29 14:30:12,456 |
%(name)s | Logger name | myapp.database |
%(levelname)s | Severity level | INFO, WARNING, ERROR |
%(message)s | The actual log message | Database query completed |
%(funcName)s | Name of function that logged | connect_to_db |
%(filename)s | Source filename | database.py |
%(lineno)d | Line number in source | 42 |
%(module)s | Module name | database |
%(process[=]d | Process ID | 12345 |
%(thread)d | Thread ID | 140256789012345 |
Here are some practical format examples:
# formatting_examples.py
import logging
logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)
# Example 1: Detailed format with function and line number
handler1 = logging.StreamHandler()
formatter1 = logging.Formatter(
"%(asctime)s [%(levelname)s] %(funcName)s:;%(lineno)d - %(message)s"
)
handler1.setFormatter(formatter1)
# Example 2: Compact format (good for production)
handler2_formatter = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
# Example 3: Include module name (useful in multi-file projects)
handler3_formatter = (
"[%(asctime)s] %(module)s - %(levelname)s - %(message)s"
)
# Example 4: ISO 8601 timestamp with timezone
handler4 = logging.StreamHandler()
formatter4 = logging.Formatter(
"%(asctime)s - %(levelname)s - %(message)s",
datefmt="%Y-%m-%dT%H:%M:%S"
)
handler4.setFormatter(formatter4)
logger.addHandler(handler1)
def process_payment(user_id):
logger.info(f"Processing payment for user {user_id}")
logger.debug("Validating card information")
logger.info("Payment submitted to processor")
return True
process_payment(12345)
Output (Example 1 format):
2026-03-29 14:32:45,123 [INFO] process_payment:55 - Processing payment for user 12345
2026-03-29 14:32:45,124 [DEBUG] process_payment:56 - Validating card information
2026-03-29:0;( 14:32:45,125 [INFO] process_payment:57 - Payment submitted to processor
Controlling Log File Size with Log Rotation
If your application runs 24/7 and logs every request, your log files can grow huge in notime, wasting disk space. The solution is CotatingFileRotationHandler, which automatically recicycles old log files:
# log_rotation_example.py
import logging
i¤©ort logging.handlers # Important!i
logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)
# Use RotatingFileHandler instead of FileHandler!
# Makes a new file every 000 1000 messages or 1 MB, whichever comes first
# Keeps an other to backup files
rotating_handler = logging.handlers.RotatingFileHandler(
filename="app.log",
maxBytes=1048576, # 1 MB (optional)
backupCount=5 # Keep up to 5 backup files
)
# Take the same formatter as before
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
rotating_handler.setFormatter(formatter)
logger.addHandler(rotating_handler)
# Now you can log directly without worrying about file size!
for i in range(10000):
logger.info(f"Processing request {i}")
# app.log will be rotated to: app.log.1, app.log.2, etc. as it grows past 1 MB
//_The oldest backups are deleted automatically staying under 10 MB total.
Output (logs directory):
- WF app.log (1 MB)
- WF app.log.1 (1 MB)
- WF app.log.2 (500 KB)
- WF app.log.3 (450 KB)
- WF app.log.4 (425 KB)
- WF app.log.5 (400 KB)
(project has processed ~6350KB = 63.5 MB since rotation started)
The rotating handler automatically deletes oldest files when it exceeds the backupCount - saving space.
Logging in Multi-File, Multi-Module Projects
For anything beyond a tiny script, use hierarchical logger names based on the module structure:
45,125 [INFO] process_payment:57 – Payment submitted to processorThe detailed format is invaluable when debugging: you know exactly which function logged the message and on which line. For production systems receiving hundreds of requests per second, the compact format reduces file size while keeping essential information.
Preventing Massive Log Files with RotatingFileHandler
If your application runs 24/7, a single FileHandler will eventually create a multi-gigabyte log file. The solution is RotatingFileHandler, which automatically archives old log files and starts a new one when the current file reaches a size limit.
# rotating_file_handler_example.py
import logging
from logging.handlers import RotatingFileHandler
import os
logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)
# Create log directory
log_dir = "logs"
if not os.path.exists(log_dir):
os.makedirs(log_dir)
# RotatingFileHandler: max 1 MB per file, keep 5 backups
rotating_handler = RotatingFileHandler(
filename=os.path.join(log_dir, "app.log"),
maxBytes=1024 * 1024, # 1 MB
backupCount=5 # Keep app.log.1, app.log.2, ..., app.log.5
)
rotating_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
rotating_handler.setFormatter(formatter)
logger.addHandler(rotating_handler)
# Simulate some logging activity
for i in range(100):
logger.info(f"Processing item {i}: " + "X" * 100) # Verbose message
When app.log reaches 1 MB, the handler automatically renames it to app.log.1, creates a fresh app.log, and continues logging. After 5 rotations, the oldest file is deleted. This keeps your disk usage bounded while preserving recent log history.
For time-based rotation (e.g., “create a new log file each day”), use TimedRotatingFileHandler:
# timed_rotating_file_handler_example.py
import logging
from logging.handlers import TimedRotatingFileHandler
import os
logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)
log_dir = "logs"
if not os.path.exists(log_dir):
os.makedirs(log_dir)
# Create a new log file every day at midnight
timed_handler = TimedRotatingFileHandler(
filename=os.path.join(log_dir, "app.log"),
when="midnight", # Rotate at midnight
interval=1, # Every 1 day
backupCount=7 # Keep 7 days of logs
)
timed_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
timed_handler.setFormatter(formatter)
logger.addHandler(timed_handler)
logger.info("Daily log rotation is configured")
The `when` parameter accepts values like "midnight" (daily), "W0" (Monday), "H" (hourly), etc. This is the preferred approach for long-running services where you want to correlate logs with calendar time.
Real-World Pattern: Logging in Multi-Module Projects
Most projects have multiple modules. The best practice is to:
- Configure logging once in your main module (or in a centralized config module)
- In each module, create a logger with
logging.getLogger(__name__) - Log directlyâno need to pass handlers around
Here’s how it works:
File: config.py (centralized logging setup)
# config.py
import logging
import logging.handlers
import os
def setup_logging():
"""Configure logging for the entire application."""
# Root logger
root_logger = logging.getLogger()
root_logger.setLevel(logging.DEBUG)
# Create logs directory
log_dir = "logs"
if not os.path.exists(log_dir):
os.makedirs(log_dir)
# File handler (all messages)
file_handler = logging.handlers.RotatingFileHandler(
filename=os.path.join(log_dir, "app.log"),
maxBytes=5 * 1024 * 1024, # 5 MB
backupCount=10
)
file_handler.setLevel(logging.DEBUG)
# Console handler (warnings only)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.WARNING)
# Formatter
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)
# Attach handlers
root_logger.addHandler(file_handler)
root_logger.addHandler(console_handler)\ÜÙ[HB]\ÈÝ]\ÈÚÈB^Ù\^Ù\[Û\ÈNÙÙÙ\\Ü\]Y\ÝZ[YÙ_HBZ\ÙOØÛÙOÜOÝÛÏ[NXZ[H
\XØ][Û[HÚ[
OÜÝÛÏÜOÛÙOÈXZ[B[\ÜÙÙÚ[ÂÛHÛÛYÈ[\ÜÙ]\ÛÙÙÚ[Â[\Ü]X\ÙB[\Ü\BÈÛÛYÝ\HÙÙÚ[ÈÓÑH]Ý\\Ù]\ÛÙÙÚ[Ê
BÙÙÙ\HÙÙÚ[ËÙ]ÙÙÙ\×Û[YW×ÊBYXZ[
NÙÙÙ\[Ê\XØ][ÛÝ\YBÈ[Ù[\È]]ÛX]XØ[H\ÙHHÛÛYÝ\YÙÙÚ[ÂY]X\ÙKÛÛXÝÝ×Ù]X\ÙJØØ[ÜÝ
MÌN]X\ÙK^XÝ]WÜ]Y\JÑSPÕ
ÓH\Ù\ÈSRULBN\Ý[H\K[WÜ\]Y\Ý
Ø\KÝ\Ù\ÈBÙÙÙ\[ÊTH]\YÜ\Ý[HB^Ù\^Ù\[Û\ÈNÙÙÙ\^Ù\[ÛTH\ÜÙ_HBÙÙÙ\[Ê\XØ][ÛÚ]ÝÛBY×Û[YW×ÈOH×ÛXZ[×ÈXZ[
OØÛÙOÜOÝÛÏÝ]]
ÈÛÛÛÛJNÜÝÛÏÜOÛÙOLËLHMÍNLÈHÛÝHSÈH\XØ][ÛÝ\YLËLHMÍNLHH]X\ÙHHSÈH]X\ÙHÛÛXÝ[Û\ÝX\ÚYLËLHMÍNLÈH]X\ÙHHSÈH]Y\H^XÝ]YÝXØÙ\ÜÙ[BLËLHMÍNLHH\HHSÈH\]Y\ÝØÙ\ÜÙYÝXØÙ\ÜÙ[BLËLHMÍNLÌHH×ÛXZ[×ÈHSÈHTH]\YÉÜÝ]\ÉÎ ÛÚÉßBLËLHMÍNLÌÈH×ÛXZ[×ÈHSÈH\XØ][ÛÚ]ÝÛØÛÙOÜOÝÛÏÝ]]
Ü][ÈÙÜËØ\ÙÊNÜÝÛÏÜOÛÙOLËLHMÍNLH×ÛXZ[×ÈHSÈH\XØ][ÛÝ\YLËLHMÍNLHH]X\ÙHHSÈHÛÛXÝ[ÈÈ]X\ÙH]ØØ[ÜÝMÌLËLHMÍNLH]X\ÙHHPQÈH\Ú[ÈÛÛXÝ[Û[Y[Ý]ÙÌÙXÛÛÂLËLHMÍNLÈH]X\ÙHHSÈH]X\ÙHÛÛXÝ[Û\ÝX\ÚYLËLHMÍNLH]X\ÙHHPQÈH^XÝ][È]Y\NÑSPÕ
ÓH\Ù\ÈSRULLËLHMÍNLHH]X\ÙHHSÈH]Y\H^XÝ]YÝXØÙ\ÜÙ[BLËLHMÍNLH\HHSÈHXÙZ]Y\]Y\ÝØ\KÝ\Ù\ÂLËLHMÍNLÈH\HHPQÈH[Y][È\]Y\Ý\[Y]\ÂLËLHMÍNLH\HHSÈH\]Y\ÝØÙ\ÜÙYÝXØÙ\ÜÙ[BLËLHMÍNLHH×ÛXZ[×ÈHSÈHTH]\YÉÜÝ]\ÉÎ ÛÚÉßBLËLHMÍNLÌHH×ÛXZ[×ÈHSÈH\XØ][ÛÚ]ÝÛØÛÙOÜOHÙ^H[ÚYÚH\Ú[ÈÛÙOÙÙÙ\HÙÙÚ[ËÙ]ÙÙÙ\×Û[YW×ÊOØÛÙO[XXÚ[Ù[KÙÙÙ\È\H]]ÛX]XØ[HY\\ÚXØ[ÛÙO\KOØÛÙOÜÈÙÙÙ\\È[YYÛÙO\HØÛÙOÛÙO]X\ÙKOØÛÙOÜÈ\ÈÛÙO]X\ÙHØÛÙO[[Ù[H\ÜXÝHÛÛYÝ\][ÛÙ][ÛÙOÛÛYËOØÛÙO[ÝHÛÛYÝ\HÛÙNÈ]\H[Ù[HÙ]ÈH[\È[ÜX][È]]ÛX]XØ[KÜKKHSPQÑWÔPÑRÓT\Ú]XÝ]Y]Ú[ÈY\[ÈÙHZ[[ÈÚ]][\HÛÜËØ\[ÛÛHÙÙÚ[ÈÛÛYÝ\][ÛÞ[ÈÙ[Ù[\ËY\\ÚXØ[ÙÙÙ\È[HHÛÛÜ[][ÛKOYHÛÛ[[Û[Z\ÝZÙ\ÈÛÛ[[ÛZ\ÝZÙ\È[XYÙÚ[È\ÏÚÈYHZ\ÝZÙKY\XØ]KZ[\ÈZ\ÝZÙHN\XØ]H[\È
\XØ]HÙÈY\ÜØYÙ\ÊOÚÏH[ÜÝÛÛ[[ÛYÎ[ÝHYH[\]Y\ÜØYÙ\È\X\ÚXÙK\È\ÝX[H\[ÈÚ[[ÝHØ[ÛÙOÙ]\ÛÙÙÚ[Ê
OØÛÙO][\H[Y\ÎÜOÛÙOÈÔÓÈHÚ[Ø]\ÙH\XØ]HY\ÜØYÙ\ÂÙ]\ÛÙÙÚ[Ê
BÙ]\ÛÙÙÚ[Ê
HÈÛÜÈHYY[\ÈYØZ[ØÛÙOÜOÛÛ][ÛØ[Ù]\ÛÙH]\XØ][ÛÝ\\Y[ÝIÜH[H\ÝÝZ]KÛX\[\È]ÙY[\ÝÎÜOÛÙOÈÛX\^\Ý[È[\ÈYÜHXÛÛYÝ\[ÂÙÙÙ\HÙÙÚ[ËÙ]ÙÙÙ\
BÜ[\[ÙÙÙ\[\ÖÎNÙÙÙ\[[ÝR[\[\OØÛÙOÜOÈYHZ\ÝZÙK]ÜÛË[ÙÙÙ\[[YHZ\ÝZÙHÜÛÈÙÙÙ\[YOÚÏY[ÝHÈÛÙOÙÙÚ[ËÙ]ÙÙÙ\\ÛÙYÛ[YHOØÛÙO[ÝXYÙÛÙOÙÙÚ[ËÙ]ÙÙÙ\×Û[YW×ÊOØÛÙO[ÝHÜÙHHX[]HÈ[\H[Ù[K[Ø^\È\ÙHÛÙO×Û[YW×ÏØÛÙOÜOÛÙOÈÔÓÂÙÙÙ\HÙÙÚ[ËÙ]ÙÙÙ\^X\HÈ[[Ù[\È[YY^X\ÈQÒÙÙÙ\HÙÙÚ[ËÙ]ÙÙÙ\×Û[YW×ÊHÈXXÚ[Ù[H\È]ÈÝÛÙÙÙ\ØÛÙOÜOÈYHZ\ÝZÙKYÜÙ][ËYÜX]\Z\ÝZÙHÎÈÜX]\
[Y\Ý[\ÈZ\ÜÚ[ÊOÚÏY[ÝHYH[\]ÛÝÙ]HÜX]\[ÝIÛÙ]H\HY\ÜØYÙHÚ]È[Y\Ý[\ÜÛÛ^ÜOÛÙOÈÝ]]Ú]Ý]ÜX]\ØÙ\ÜÚ[È][HBÈÝ]]Ú]ÜX]\LËLHMÍNLÈH×ÛXZ[×ÈHSÈHØÙ\ÜÚ[È][HOØÛÙOÜO[Ø^\È]XÚHÜX]\È[\È]Ü]HÈ[\ËÛÛÛÛH[\ÈØ[ÛÜÈÚ]Ý]]] ÜÈ]\È]HÛÛÚ\Ý[ÜX][È]\]Ú\KÜÈYHZ\ÝZÙKZ[\[][]Ë[ÙÙÙ\[][Z\ÝZÙH
ÛÛ\Ú[È[\][ÈÙÙÙ\][ÚÏXXÚÙÙÙ\[XXÚ[\\È]ÈÝÛ][Ý[\È\NÜOÛÙOÈÙÙÙ\][PQÈH[ÝÜÈ]\][ÈÝYÚÈ[H[\][SÈH[\ÈÈSÈ[XÝBÈ\Ý[PQÈY\ÜØYÙ\ÈÛÈÈÛÛÛÛH]Õ[BÙÙÙ\Ù]][
ÙÙÚ[ËPQÊB[WÚ[\Ù]][
ÙÙÚ[ËSÊBÙÙÙ\XYÊ\ÈXXÚ\ÈÛÛÛÛH]Ý[HHÈÛÛ\Ú[ÈOØÛÙOÜO\ÝXÝXÙNÙ]HÙÙÙ\][ÈPQÈ
HÝÙ\Ý
K[[\]XXÚ[\ÜOÛÙOÙÙÙ\Ù]][
ÙÙÚ[ËPQÊHÈ][\ÈXÚYHÚ]ÈÙY\[WÚ[\Ù]][
ÙÙÚ[ËPQÊHÈ[HÙ]È]\][ÂÛÛÛÛWÚ[\Ù]][
ÙÙÚ[ËÐTSÊHÈÛÛÛÛHÙ]ÈØ\[ÜÈÛOØÛÙOÜOÈYHZ\ÝZÙKY^Ù\[ÛË[Ý[ÙÙÙYZ\ÝZÙH
N^Ù\[ÛÈÛÝ[ÛYHXÙXXÚÜÏÚÏ\ÙHÛÙOÙÙÙ\^Ù\[Û
OØÛÙO
ÝÛÙOÙÙÙ\\Ü
OØÛÙOHÚ[ÙÙÚ[È[ÚYH[^Ù\[Û[\È[ÛYHH[XÙXXÚÎÜOÛÙOÈÔÓÈHÈXÙXXÚÂN\ÚÞWÛÜ\][Û
B^Ù\^Ù\[Û\ÈNÙÙÙ\\ÜZ[YÙ_HBÈQÒH[ÛY\È[XÙXXÚÂN\ÚÞWÛÜ\][Û
B^Ù\^Ù\[Û\ÈNÙÙÙ\^Ù\[ÛZ[YÙ_HOØÛÙOÜOÝÛÏÝ]]Ú]ÙÙÙ\^Ù\[Û
NÜÝÛÏÜOÛÙOTÔHZ[Y]\Ú[ÛH\ÂXÙXXÚÈ
[ÜÝXÙ[Ø[\Ý
N[HXZ[H[HL[XZ[\ÚÞWÛÜ\][Û
B[H][ËH[H
K[\ÚÞWÛÜ\][Û]\LÈ\Ñ]\Ú[Û\Ü]\Ú[ÛH\ÏØÛÙOÜOYHX[[YKY^[\HX[SYH^[\NHÙXØÜ\\Ú]ÛÛ\Z[Ú]HÙÙÚ[ÏÚ] ÜÈZ[HX[\ÝXÈÚXÝHÙXØÜ\\]ÙÜÈÈÝ[H[ÛÛÛÛHÚ]Ý][Û[\È\ÜÈÜXÙY[K[ÝY\È]Z[YXYÙÚ[È[ÜX][ÛÜKKHSPQÑWÔPÑRÓTÜY\ÙXÚ]]HÚ[ÈZ[ÈØ\\Y[ÜØ[^YØ\[ÛÙXØÜ\\È[ÈHÝÛÛÙÙÙÚ[È\ÈÚ]\[È[[YÙ[ÙKKOOÛÙOÈÙXÜØÜ\\ÝÚ]ÛÙÙÚ[ËB[\ÜÙÙÚ[Â[\ÜÙÙÚ[Ë[\Â[\ÜÜÂ[\Ü[YBÛH\X\]Y\Ý[\Ü\Ü[ÛH\X\Ü[\ÜT\Ü[\ÜÛÛÈÛÛYÝ\HÙÙÚ[ÂYÙ]\ÛÙÙÚ[Ê
NÙÙÙ\HÙÙÚ[ËÙ]ÙÙÙ\ÙXØÜ\\BÙÙÙ\Ù]][
ÙÙÚ[ËPQÊBÙ×Ù\HÙÜÈYÝÜË]^\ÝÊÙ×Ù\NÜËXZÙY\ÊÙ×Ù\BÈ[H[\[Y\ÜØYÙ\ËÝ]\È]P[WÚ[\HÙÙÚ[Ë[\ËÝ][Ñ[R[\[[[YO[ÜË]Ú[Ù×Ù\ØÜ\\ÙÈKX^]\ÏL
L
LXÚÝ\ÛÝ[MB
B[WÚ[\Ù]][
ÙÙÚ[ËPQÊBÈÛÛÛÛH[\Ø\[ÜÈÛBÛÛÛÛWÚ[\HÙÙÚ[ËÝX[R[\
BÛÛÛÛWÚ[\Ù]][
ÙÙÚ[ËÐTSÊBÈÜX]\Ú]]Z[Y[ÂÜX]\HÙÙÚ[ËÜX]\J\ØÝ[YJ\ÈÉJ][[YJ\×H J[Ó[YJ\ÎJ[[ÊYH JY\ÜØYÙJ\È]Y]HVKI[KIY RSNTÈ
B[WÚ[\Ù]ÜX]\ÜX]\BÛÛÛÛWÚ[\Ù]ÜX]\ÜX]\BÙÙÙ\Y[\[WÚ[\BÙÙÙ\Y[\ÛÛÛÛWÚ[\B]\ÙÙÙ\ÙÙÙ\HÙ]\ÛÙÙÚ[Ê
BY]ÚÚÛÛ\[Y[Ý]MJN]Ú[\ÙHÓÓÛHHTÙÙÙ\XYÊ][\[ÈÈ]ÚÝ\HBNÚ]\Ü[\[Y[Ý]][Y[Ý]
H\È\ÜÛÙN]HHÛÛØYÊ\ÜÛÙKXY
KXÛÙJ]NJBÙÙÙ\[ÊÝXØÙ\ÜÙ[H]ÚYÛ[]J_HXÛÜÈÛHÝ\HB]\]B^Ù\T\Ü\ÈNÙÙÙ\\Ü]ÛÜÈ\Ü]Ú[ÈÝ\NÙ_HB]\ÛB^Ù\ÛÛÓÓXÛÙQ\Ü\ÈNÙÙÙ\\ÜZ[YÈ\ÙHÓÓÛHÝ\NÙ_HB]\ÛB^Ù\^Ù\[Û\ÈNÙÙÙ\^Ù\[Û[^XÝY\Ü]Ú[ÈÝ\HB]\ÛBYØÙ\Ü×Ù]J]JNØÙ\ÜÈ]ÚY]KYÝ]NÙÙÙ\Ø\[ÊÈ]HÈØÙ\ÜÈB]\ÙÙÙ\[ÊØÙ\ÜÚ[ÈÛ[]J_H][\ÈBØÙ\ÜÙYHÜK][H[[[Y\]J]JNNÈÚ[][]HØÙ\ÜÚ[ÂY\Ú[Ý[ÙJ][KXÝ
NØÙ\ÜÙY
ÏHBYH HLOHÙÙÙ\XYÊØÙ\ÜÙYÚ_H][\ÈB^Ù\^Ù\[Û\ÈNÙÙÙ\Ø\[ÊZ[YÈØÙ\ÜÈ][HÚ_NÙ_HBÙÙÙ\[ÊÝXØÙ\ÜÙ[HØÙ\ÜÙYÜØÙ\ÜÙYKÞÛ[]J_H][\ÈB]\ØÙ\ÜÙYYXZ[
NÙÙÙ\[ÊÙXØÜ\\Ý\YBÈ]ÚÛHÓÓXÙZÛ\
YHZÙHÓÓTJB\HÎËÚÛÛXÙZÛ\\XÛÙKÛÛKÜÜÝÈÙÙÙ\XYÊÛÛYÝ\][Û[Y[Ý]M\ËX^Ü]Y\ÏLÈB]HH]ÚÚÛÛ\
BY]NØÙ\ÜÙYHØÙ\Ü×Ù]J]JBÙÙÙ\[ÊØÜ\[ÈÛÛ\]YÜØÙ\ÜÙYH][\ÈØÙ\ÜÙYB[ÙNÙÙÙ\\ÜØÜ\[ÈZ[Y[XHÈ]Ú]HBÙÙÙ\[ÊÙXØÜ\\[\ÚYBY×Û[YW×ÈOH×ÛXZ[×ÈNXZ[
B^Ù\Ù^XØ\[\\ÙÙÙ\Ø\[ÊØÜ\\[\\YH\Ù\B^Ù\^Ù\[Û\ÈNÙÙÙ\^Ù\[Û][\Ü[XZ[BZ\ÙOØÛÙOÜOÝÛÏÝ]]
ÈÛÛÛÛJNÜÝÛÏÜOÛÙOLËLHMMHÒS×HXZ[HÙXØÜ\\Ý\YLËLHMMÒS×H]ÚÚÛÛHÝXØÙ\ÜÙ[H]ÚYLXÛÜÈÛHÎËÚÛÛXÙZÛ\\XÛÙKÛÛKÜÜÝÂLËLHMMÒS×HØÙ\Ü×Ù]NHØÙ\ÜÚ[ÈL][\ÂLËLHMMÒS×HØÙ\Ü×Ù]NHÝXØÙ\ÜÙ[HØÙ\ÜÙYLÌL][\ÂLËLHMMÒS×HXZ[ÈHØÜ\[ÈÛÛ\]YL][\ÈØÙ\ÜÙYLËLHMMÒS×HXZ[
HÙXØÜ\\[\ÚYØÛÙOÜOÝÛÏÝ]]
[ÙÜËÜØÜ\\ÙÊNÜÝÛÏÜOÛÙOLËLHMMHÒS×HXZ[HÙXØÜ\\Ý\YLËLHMMHÑPQ×HXZ[HÛÛYÝ\][Û[Y[Ý]M\ËX^Ü]Y\ÏLÂLËLHMMHÑPQ×H]ÚÚÛÛHH][\[ÈÈ]ÚÎËÚÛÛXÙZÛ\\XÛÙKÛÛKÜÜÝÂLËLHMMÒS×H]ÚÚÛÛHÝXØÙ\ÜÙ[H]ÚYLXÛÜÈÛHÎËÚÛÛXÙZÛ\\XÛÙKÛÛKÜÜÝÂLËLHMMÒS×HØÙ\Ü×Ù]NHØÙ\ÜÚ[ÈL][\ÂLËLHMMÑPQ×HØÙ\Ü×Ù]NHHØÙ\ÜÙY][\ÂLËLHMMÑPQ×HØÙ\Ü×Ù]NHHØÙ\ÜÙYL][\ÂLËLHMMÑPQ×HØÙ\Ü×Ù]NHHØÙ\ÜÙY][\Â
[ÜHXYÈY\ÜØYÙ\ÊBLËLHMMÑPQ×HØÙ\Ü×Ù]NHHØÙ\ÜÙYL][\ÂLËLHMMÒS×HØÙ\Ü×Ù]NHÝXØÙ\ÜÙ[HØÙ\ÜÙYLÌL][\ÂLËLHMMÒS×HXZ[ÈHØÜ\[ÈÛÛ\]YL][\ÈØÙ\ÜÙYLËLHMMÒS×HXZ[
HÙXØÜ\\[\ÚYØÛÙOÜO\È^[\H[[ÛÝ]\È\ÝXÝXÙ\ÎÙ]\ÙÙÚ[ÈÛÙK\ÙH[Ù[K[][ÙÙÙ\Ú]ÛÙO×Û[YW×ÏØÛÙO[H^Ù\[ÛÈÚ]ÛÛ^[ÛYHXYË[][XYÛÜÝXÜÈÜÝX\ÚÛÝ[Ë[\ÙHSÈY\ÜØYÙ\ÈÈXÚÈH\H]Ú[HØ[HØØÝ\ËHXYÈÙÈ\È[H]Z[ÎÈHÛÛÛÛHÝ^\È]ZY][[ÛÛY][ÈXÝX[HÛÙ\ÈÜÛËÜYH\H\]Y[H\ÚÙY]Y\Ý[ÛÏÚÈYH\KX\ÚXØÛÛYÈNÚHÙ\È\ÚXÐÛÛYÈÛÛY][Y\ÈÝÛÜÏÏÚÏÛÙOÙÙÚ[Ë\ÚXÐÛÛYÊ
OØÛÙOÛÛYÝ\\ÈHÛÝÙÙÙ\]ÛHYÈ[\È]HY[YYY]ÛÙH[ÝHYH[\
][[HX\H[ÝIÜH\Ú[ÊKÛÙO\ÚXÐÛÛYÊ
OØÛÙOXÛÛY\ÈHË[ÜÜ\ÈX\ÛÛ]ÚYÛÙO\ÚXÐÛÛYÊ
OØÛÙO[ÙXÝ[ÛÛÙK[ÝXY\ÙHH]\ÛHH][K[[Ù[H^[\NÜX]HHÙ]\[Ý[Û]ÛÛYÝ\\È[\È^XÚ]HÛHÛÝÙÙÙ\ÜÈYH\K\\ÜX[ÙHNÙ\ÈÙÙÚ[È\\ÜX[ÙOÏÚÏÝÚYÛYXØ[KHÙÙÚ[È[Ù[H\ÈÜ[Z^Y[[ÝHØ[\ØXH^[Ú]HÜ\][ÛËY[ÝIÜHÛÛÙ\Y\ÙH^H][X][ÛÛÙOÙÙÙ\XYÊ[YNÙ^[Ú]WÙ[Ý[Û
_HOØÛÙOÛHØ[ÈH[Ý[ÛYPQÈ\È[XY[\]][KÚXÚÈH][\ÝÛÙOYÙÙÙ\\Ñ[XYÜÙÙÚ[ËPQÊNÙÙÙ\XYÊOØÛÙOÜ[ÜÝ\XØ][ÛËÙÙÚ[È\ÈYÛYÚXHÝ\XYÜÈYH\K]XY\ØYHN\ÈÙÙÚ[ÈXY\ØYOÏÚÏY\ËHÙÙÚ[È[Ù[H\Ù\ÈØÚÜÈ[\[HÈÛÛÜ[]HXØÙ\ÜÈÈ[\Ë[ÝHØ[ØY[HØ[ÙÙÙ\Y]ÙÈÛH][\HXYÈÚ]Ý]ÛÜ\[ÛÝÙ]\H[\È[\Ù[\È
\ÜXÚX[HÝ\ÝÛH[\ÊHÚÝ[[ÛÈHXY\ØYKZ[Z[[\ÈZÙHÛÙO[R[\ØÛÙO\HØYKÜÈYH\K[ÙËYÜX]]ÚÙ[ÈNÚ]Ý\ÜX]ÚÙ[È\H]Z[XH^[ÛHÛÛ[[ÛÛ\ÏÏÚÏX[KÛÙOJ][ÊYØÛÙO
[Y\XÈ][
KÛÙOJ][YJ\ÏØÛÙO
[[H]
KÛÙOJØÙ\ÜÓ[YJ\ÏØÛÙO
ØÙ\ÜÈ[YJKÛÙOJXY[YJ\ÏØÛÙO
XY[YJK[ÛÙOJ\ÙXÜÊYØÛÙO
Z[\ÙXÛÛÊKÙYHHÙXÚX[]ÛØÝ[Y[][ÛÜHÛÛ\]H\Ý[ÜÝÚXÝÈÝXÚÈÚ]HÚÙ[ÈÚÝÛX\Y\XØ]\ÙH^IÜHH[ÜÝ\ÙY[ÜÈYH\KY\ØXK[X\K[ÙÜÈNÝÈÈHÚ[[ÙH\ÜÙHÙÜÈÛH\\\HX\Y\ÏÏÚÏÙ]HÙÙÙ\Ü]X\HÈHYÚ\][X\Y\È\ÙHÛÙOÙÙÚ[ËÙ]ÙÙÙ\×Û[YW×ÊOØÛÙOÛÈ[ÝHØ[ÎÛÙOÙÙÚ[ËÙ]ÙÙÙ\\]Y\ÝÈKÙ]][
ÙÙÚ[ËÐTSÊOØÛÙOÈÚ[[ÙHH\]Y\ÝÈX\K\È\ÈHÛÛ[[Û]\Ú[[YÜ][È][\HX\Y\È]ÙÈX][KÜÈYH\K\Þ\ÛÙÈNÝÈÈHÙÈÈÞ\ÛÙÈÜÝ\[ÝÏÚÏ\ÙHÛÙOÙÙÚ[Ë[\ËÞ\ÓÙÒ[\ØÛÙO[ÝXYÙÛÙO[R[\ØÛÙOÛ[^Ó[^Þ\Ý[\ÎÛÙO[\HÙÙÚ[Ë[\ËÞ\ÓÙÒ[\Y\ÜÏJ ËÙ]ÛÙÉË
JOØÛÙOÛÞ\Ý[\ÈÚ]Ý\[Ý\ÙHÛÙOÞ\ÓÙÒ[\Y\ÜÏJ ÛØØ[ÜÝ Ë
LM
JOØÛÙO\È\È[\Ü[ÜÛË\[[ÈÙ\XÙ\È]Þ\Ý[YX[YÙ\ËÜYHÛÛÛ\Ú[ÛÛÛÛ\Ú[ÛÚ[ÝHÝÈ[\Ý[ÝÈÈ[Ý[Y[]Û\XØ][ÛÈÚ]Ù\ÜÚ[Û[YÜYHÙÙÚ[Ë[ÝIÝHX\YÈÜX]HÙÙÙ\Ë]XÚ[\ÈÜ[H[ÛÛÛÛHÝ]]ÜX]Y\ÜØYÙ\ÈÚ][Y\Ý[\È[ÛÛ^Ý]HÙÈ[\ÈÈ][[]Ø^H\ÚÈ\ØYÙK[ÛÛÜ[]HÙÙÚ[ÈXÜÜÜÈ][\H[Ù[\È[HX[ÚXÝÜHÙ^HZÙX]Ø^NÙÙÚ[È\ÈÝH^\NÈ] ÜÈ\ÜÙ[X[[\ÝXÝ\KÛÙO[
OØÛÙOÝ][Y[È]\Ü]KÙÈ[\È\H\X[[XÛÜÈÙÚ][Ý\\XØ][ÛYÚ[]Y][Ú]Ù[ÜÛËHÛÝÚ[ÈH]\È[\È\XÛx %\ÜXÚX[HH][K[[Ù[HÙ]\[ÛÛYËX8 %[ÝHZ[\XØ][ÛÈ]\HX\ÞHÈXYÈ[ÙXÝ[ÛÜZÙHHÙXØÜ\\^[\H[^[]Y[ÜHÛÛ\^\Ü[[ËÙÈY]XÜÈ
]Y\Y\È\ÙXÛÛ]\ÈØÙ\ÜÙY
K^\[Y[Ú]Y\[[\È
[XZ[[\ÈÜÜ]XØ[\ÜËÜ^[\JKHÙÙÚ[È[Ù[H\È^XH[ÝYÚÈÜÝÈÚ][Ý\ÚXÝÜÜÛÛ\]HØÝ[Y[][ÛÛ[[\È[ÜX]\ËÙYHHÙXÚX[HYHÎËÙØÜË]ÛÜËÌËÛX\KÛÙÙÚ[Ë[]ÛÙÙÚ[ÈØÝ[Y[][ÛØOÜYH[]YX\XÛ\È[]Y\XÛ\ÏÚ[OHYHÎËÜ]ÛÝÝÜÙÜ[KÛÛKÙ^Ù\[ÛZ[[ËZ[\]Û]KY^Ù\Y[ÙKY[[KÈ^Ù\[Û[[È[]Û
K^Ù\[ÙK[[JOØOÛOOHYHÎËÜ]ÛÝÝÜÙÜ[KÛÛKÜ]ÛYXÛÜ]ÜËZÝË]ËXÜX]KX[]\ÙKÈ]ÛXÛÜ]ÜÎÝÈÈÜX]H[\ÙOØOÛOOHYHÎËÜ]ÛÝÝÜÙÜ[KÛÛKÜ]ÛZÛÛ\\Ú[ËX[\ØÙ\ÜÚ[ËÈ]ÛÓÓ\Ú[È[ØÙ\ÜÚ[ÏØOÛOÝ[ËÙ]ÜÝ^VËÙ]ÜØÛÛ[[VËÙ]ÜÜÝ×VËÙ]ÜÜÙXÝ[ÛBKKHÝÜ]KÜXÙZÛ\KO
Related Python Tutorials
Continue learning with these related guides: