How to write scripts in Python

Learn to write Python scripts with this guide. Explore different methods, tips, real-world applications, and how to debug common errors.

How to write scripts in Python
Published on: 
Tue
Mar 10, 2026
Updated on: 
Fri
Mar 13, 2026
The Replit Team

To write scripts in Python is a fundamental skill for developers. You can automate tasks, build applications, and solve complex problems with just a few lines of code.

Here, you'll explore core techniques and practical tips. You will also find real-world applications and essential advice to debug your code and write with confidence from the start.

Creating a simple script

# hello_world.py
print("Hello, World!")
print("This is my first Python script")--OUTPUT--Hello, World!
This is my first Python script

This classic hello_world.py script is a foundational example. It’s not just about printing text; it’s about demonstrating a script's core behavior. The Python interpreter reads the file from top to bottom, executing each line in sequence.

  • Each print() function call outputs its argument directly to the console.
  • A new line is automatically added after each statement, which is standard behavior you can rely on for formatting console text.

Essential scripting techniques

Moving beyond that first script, you can build more powerful and interactive programs by using command-line arguments, reading and writing files, and organizing your code.

Using command-line arguments with sys.argv

import sys

script_name = sys.argv[0]
arguments = sys.argv[1:]
print(f"Script name: {script_name}")
print(f"Arguments: {arguments}")--OUTPUT--Script name: script.py
Arguments: ['arg1', 'arg2', 'arg3']

The sys.argv list is your gateway to creating interactive command-line tools. It captures all the arguments passed to your script when it's executed, allowing you to build flexible programs that don't require hardcoded values.

  • The list's first element, sys.argv[0], always contains the name of the script itself.
  • Any subsequent elements are the arguments you provide, which you can access using list slicing like sys.argv[1:].

Reading and writing files

# Open a file for writing
with open("data.txt", "w") as file:
   file.write("Line 1: Python scripting is fun\n")
   file.write("Line 2: It's easy to work with files")

# Read the file contents
with open("data.txt", "r") as file:
   content = file.read()
   print(content)--OUTPUT--Line 1: Python scripting is fun
Line 2: It's easy to work with files

The with open() statement is a robust way to handle files. It creates a context that automatically closes the file for you once the block is exited, which helps prevent resource leaks. This approach simplifies your code and makes it more reliable.

  • Use the mode "w" to open a file for writing. This will create the file if it doesn't exist or overwrite its contents if it does.
  • The "r" mode opens an existing file for reading.
  • Methods like file.write() and file.read() let you interact with the file's contents directly.

Using functions to organize your code

def greet(name):
   return f"Hello, {name}!"

def calculate_square(number):
   return number ** 2

name = "Alice"
number = 5
print(greet(name))
print(f"The square of {number} is {calculate_square(number)}")--OUTPUT--Hello, Alice!
The square of 5 is 25

Functions are the building blocks of well-structured Python code. By wrapping logic inside functions like greet() and calculate_square(), you make your code modular and easier to manage. This approach keeps your main script clean, focusing on high-level operations rather than implementation details.

  • Each function performs a single, well-defined task.
  • You can reuse functions with different inputs, which avoids repetitive code.
  • This separation makes debugging simpler since you can test each function independently.

Advanced scripting approaches

Building on those essential techniques, you can now create more sophisticated scripts that are executable, handle errors gracefully, and offer professional command-line interfaces.

Creating executable scripts with shebang

#!/usr/bin/env python3

import os
import platform

print(f"Running on {platform.system()}")
print(f"Current working directory: {os.getcwd()}")
print(f"Python version: {platform.python_version()}")--OUTPUT--Running on Linux
Current working directory: /home/user/scripts
Python version: 3.9.5

The shebang line, #!/usr/bin/env python3, transforms your file into an executable script on Unix-like systems like Linux or macOS. It instructs the operating system to use the Python 3 interpreter to run the code, so you don't have to type python3 every time. This makes your scripts feel more like native command-line tools.

  • You first need to grant execute permissions with a command like chmod +x your_script.py.
  • After that, you can run the script directly in your terminal by typing ./your_script.py.

Implementing error handling and logging

import logging

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

try:
   result = 10 / 0
except ZeroDivisionError as e:
   logging.error(f"Error occurred: {e}")
   
logging.info("Script execution completed")--OUTPUT--2023-09-28 14:23:45,123 - ERROR - Error occurred: division by zero
2023-09-28 14:23:45,124 - INFO - Script execution completed

A robust script anticipates problems instead of crashing. The try...except block lets you gracefully handle specific errors, like the ZeroDivisionError, allowing your program to continue running. This makes your code far more resilient.

The logging module is a professional way to track your script’s execution, offering more control than simple print() statements.

  • You can configure logs with timestamps and severity levels using logging.basicConfig().
  • This allows you to record different events—like logging.error() for failures and logging.info() for status updates—making debugging much easier.

Using argparse for professional command-line interfaces

import argparse

parser = argparse.ArgumentParser(description="A sample script with arguments")
parser.add_argument("--name", default="World", help="Name to greet")
parser.add_argument("--repeat", type=int, default=1, help="Number of times to repeat")

args = parser.parse_args()
for _ in range(args.repeat):
   print(f"Hello, {args.name}!")--OUTPUT--Hello, Alice!
Hello, Alice!
Hello, Alice!

The argparse module is a significant step up from manually handling sys.argv. It provides a structured framework for defining command-line arguments, complete with types, default values, and help messages. This makes your scripts feel more professional and easier for others to use.

  • You define arguments with parser.add_argument(), specifying details like a default value or type=int.
  • argparse automatically creates a help menu that users can access with the -h or --help flag.
  • The parsed arguments are returned in an object, so you can access them cleanly with dot notation, like args.name.

Move faster with Replit

Replit is an AI-powered development platform that transforms natural language into working applications. Describe what you want to build, and Replit Agent creates it—complete with databases, APIs, and deployment.

The scripting techniques from this article are the foundation for real-world tools. Replit Agent can take these concepts and build them into production-ready applications:

  • Build a command-line utility with argparse that processes text files to count words or find specific patterns.
  • Create an automated script that reads CSV data, performs calculations using functions, and logs the results to a separate file.
  • Deploy a file management tool that takes source and destination folders as arguments and organizes files based on their type or creation date.

Describe your app idea, and Replit Agent will write the code, test it, and handle deployment, all within your browser.

Common errors and challenges

Even experienced developers run into common pitfalls, but knowing what to look for makes debugging much easier.

Fixing off-by-one errors in loops

Off-by-one errors are sneaky bugs that cause your loops to run one time too many or one time too few. They often appear when you're working with indices in lists or using the range() function. Always remember that Python uses zero-based indexing, meaning a list's first item is at index 0 and the last is at an index one less than its length. Double-checking your loop boundaries is the key to avoiding this.

Fixing TypeError when combining different data types

A TypeError pops up when you try to combine incompatible data types, like adding a number to a string with the + operator. For example, "Score: " + 100 will fail because Python doesn't automatically convert the integer to a string. You can fix this by explicitly converting the value using functions like str(), or by using f-strings, which handle the conversion for you.

Handling KeyError exceptions in dictionaries

When working with dictionaries, you'll likely encounter a KeyError. This happens if you try to access a key that doesn't exist in the dictionary. Instead of letting your script crash, you can handle this gracefully.

  • Check for the key's existence first with the in keyword, like if 'my_key' in my_dict:.
  • A cleaner approach is to use the .get() method. my_dict.get('my_key') returns None if the key is missing, or you can provide a default value like my_dict.get('my_key', 'default_value').

Fixing off-by-one errors in loops

These sneaky bugs cause loops to run one time too many or too few. They're often a result of how the range() function works, since its stop value is exclusive. Notice how the loop below stops just short of the intended number.

for i in range(1, 10):
   print(i, end=" ")

Since range(1, 10) stops just before 10, the loop only prints numbers 1 through 9. This is a classic off-by-one error. Check the corrected version below to see how to include the final number.

for i in range(1, 11):
   print(i, end=" ")

The fix is simple: increase the stop value by one. The range() function generates numbers up to, but not including, its second argument. So, range(1, 10) gives you numbers from 1 to 9. To include 10 in your loop, you must use range(1, 11). It's a common trap, so always double-check your loop boundaries, especially when working with list indices or specific numerical sequences.

Fixing TypeError when combining different data types

This error frequently happens with user input. Since the input() function returns everything as a string, you can't perform mathematical calculations directly. Multiplying two strings from user input, for example, won't give you a numerical product. The following code demonstrates this issue.

quantity = input("Enter quantity: ")
price = input("Enter price: ")

total = quantity * price
print(f"Total cost: {total}")

The issue is that the * operator attempts string repetition, not mathematical multiplication. Since you can't multiply one string by another, Python raises a TypeError. See how to get the correct numerical result in the code below.

quantity = input("Enter quantity: ")
price = input("Enter price: ")

quantity = int(quantity)
price = float(price)

total = quantity * price
print(f"Total cost: {total}")

The fix is to explicitly convert the string values from input() into numbers. By wrapping the variables in int() and float(), you ensure Python treats them as numerical data, allowing the * operator to perform mathematical multiplication correctly. You'll need to do this anytime you work with user-provided data that requires calculation, as it's almost always read as a string first.

Handling KeyError exceptions in dictionaries

A KeyError is a common roadblock when you're working with dictionaries. It happens when your code tries to access a key that doesn't exist. The script below shows how easily this can happen when you expect a key to be present.

user_data = {"name": "Alice", "email": "[email protected]"}

username = user_data["name"]
email = user_data["email"]
phone = user_data["phone"]  # Will raise KeyError

print(f"User: {username}, Email: {email}, Phone: {phone}")

Direct access with user_data["phone"] fails because the key is missing from the dictionary, which immediately stops the script. The following example shows how to prevent this crash and handle missing keys gracefully.

user_data = {"name": "Alice", "email": "[email protected]"}

username = user_data.get("name", "Unknown")
email = user_data.get("email", "No email provided")
phone = user_data.get("phone", "No phone provided")

print(f"User: {username}, Email: {email}, Phone: {phone}")

The solution is to use the dictionary’s .get() method, which lets you provide a default value if a key is missing. For example, user_data.get("phone", "No phone provided") safely returns the default string instead of raising an error. This is a clean and reliable way to handle data where some fields might not exist—such as when you're processing API responses or user-submitted forms—and keeps your script from crashing unexpectedly.

Real-world applications

With these scripting techniques and debugging strategies in hand, you can build practical tools for real-world automation and data gathering.

Analyzing file types in a directory with os

You can use Python’s os module to automatically scan a directory and count how many files of each type it contains.

import os

directory = "./documents"
extension_counts = {}
for filename in os.listdir(directory):
   if os.path.isfile(os.path.join(directory, filename)):
       ext = filename.split('.')[-1].lower()
       extension_counts[ext] = extension_counts.get(ext, 0) + 1

for ext, count in extension_counts.items():
   print(f"{ext}: {count} files")

This script inventories files by their extension. It iterates through a directory using os.listdir() and uses os.path.isfile() to ignore subdirectories, focusing only on files.

  • For each file, it isolates the extension by splitting the filename at the period and taking the last part.
  • A dictionary keeps a running tally. The .get() method cleverly increments the count for each extension or initializes it if it's the first time seeing that file type.

Finally, the script loops through the completed dictionary to print a clean summary of file counts.

Creating a simple web scraper with requests and re

You can combine the requests library to fetch web content with the re module to parse that content for specific patterns, like finding all Python version numbers on a webpage.

import requests
import re

url = "https://en.wikipedia.org/wiki/Python_(programming_language)"
response = requests.get(url)
versions = re.findall(r"Python (\d+\.\d+)", response.text)
unique_versions = set(versions)

print(f"Found {len(versions)} mentions of Python versions:")
for version in sorted(unique_versions):
   print(f"- Python {version}")

This script shows how you can quickly scrape data from a live website. It fetches the entire HTML content of a Wikipedia page using requests.get(). The real work happens with re.findall(), which scours the text for a regular expression pattern that matches Python version numbers.

  • The pattern r"Python (\d+\.\d+)" specifically looks for the word "Python" followed by a number in the "digit.digit" format.
  • Using set() is a clever trick to automatically remove any duplicate version numbers found on the page.
  • Finally, sorted() organizes the unique versions, creating a clean, ordered list for the output.

Get started with Replit

Turn these scripting skills into a real tool. Describe what you want to build, like “a script that sorts files by extension” or “a web scraper that extracts all links from a URL.”

Replit Agent will write the code, test for errors, and deploy your app. Start building with Replit.

Get started free

Create and deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.

Get started for free

Create & deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.