The OS module is part if the standard Python library and contains loads of functions for interacting with a computer's operating system, including:
Create a directory using os.makdir()
import os
os.mkdir('./data')
# now we can create a new file inside our dir
authors = ["Ursula K. Le Guin", "N. K. Jemisin", "Octavia E. Butler"]
with open("data/authors.txt", "a") as file:
for author in authors:
file.write(author + "\n")
Check what's inside a directory using os.listdir().
This function returns a list of filenames as strings.
import os
files = os.listdir('./data')
for file in file:
print(file)
The os.path module is also part if the standard Python library and contains handy functions for getting information about files, including:
If we try to create a directory that already exists, we get an error.
It's a good practice to check whether a directory exists before creating a new one using os.path.exists()
os.path.exists() returns True
or False
import os
if not os.path.exists('./data'):
os.mkdir('./data')
Sometimes you need to get just file names or extensions. Use os.path.splitext() to return a list with 2 items: the file name and the extension
import os
files = os.listdir('./data')
for file in file:
split = os.path.splitext(file)
name = split[0]
print(name)
extension = split[1]
print(extension)
The argparse module is part of the standard Python library and contains functions that allow accepting and processing command line arguments, as well as providing help text to users.
add_argument() is used to define a new argument.
A name is required, and additional parameters can also be set, such as:
import argparse
# initialize the argument parser
parser=argparse.ArgumentParser()
# define an argument
parser.add_argument('-d', '--directory',
type=str,
required=True,
help='The directory that report files are located in')
Note: 1 argument can have multiple names. It's common to support both a short -d
and long --directory
name version.
-
and --
before short and long names are not required, but they are common convention in CLI commands.
parse_args() is used to extract values passed in as arguments
import argparse
# initialize the argument parser
parser=argparse.ArgumentParser()
# define an argument
parser.add_argument('-d', '--directory',
type=str,
required=True,
help='The directory that report files are located in')
# parse the arguments
args=parser.parse_args()
# get a specifc argument value
directory = args.directory
Can we have multiple arguments? Of course!
import argparse
# initialize the argument parser
parser=argparse.ArgumentParser()
# define an argument
parser.add_argument('-d', '--directory',
type=str,
required=True,
help='The directory that report files are located in')
parser.add_argument('-n', '--name',
type=str,
required=True,
help='Your name')
# parse the arguments (parse_args() parses all arguments)
args=parser.parse_args()
# get a specifc argument value
directory = args.directory
name = args.name
The Replit Run button does the equivalent of typing python main.py
into a command line interface (CLI).
We can access the CLI in Replit by switching the right panel from Console to Shell
These are common to all programming languages:
Each programming language has syntactic rules. If the rules aren't followed, the program cannot be parsed and will not be executed at all.
Spot the syntax errors:
if x > 5 # Missing colon
x += 1
sum = 0
for x in range(0, 10):
sum + = x # No space needed between + and =
def my_func(num_1, num_2):
sum = num_1 + num_2
return sum # Return is not indented
Common syntax errors
To fix a syntax error, read the message carefully and go through your code with a critical eye. π
...and lint your code!
To avoid syntax errors, use a linting tool to check your code as you write it. Many IDEs have a Python linter built in or available as an extension (ex: VSCode Python linting).
You can also run Pylint on your code
# import pylint
# Already installed in Replit - no import needed
def sum(a, b):
total = a + b
return total
In Replit, switch to the Shell tab and type pylint main.py
and press Enter
.
When prompted to select a version, press Enter
again.
Fix this code!
A program has a logic error if it does not behave as expected. Typically discovered via failing tests or bug reports from users.
Spot the logic error:
# Which medal goes to the first place winner?
medals = ["gold", "silver", "bronze"]
first_place = medals[1]
print(first_place)
To avoid the wrath of angry users due to logic errors, write tests!
There are several Python testing frameworks. Pytest is a good one to start with.
import pytest
medals = ["gold", "silver", "bronze"]
def get_medal(place):
return medals[place]
def test_get_medal():
assert get_medal(1) == "gold"
In Replit, click Run to install Pytest, then switch to the Shell tab and type pytest main.py
and press Enter
.
Add a test with Pytest
Even with testing and linting, errors can slip through!
A runtime error happens while a program is running, often halting the execution of the program.
Spot the runtime error:
def div_numbers(dividend, divisor):
return dividend/divisor
quot1 = div_numbers(10, 2)
quot2 = div_numbers(10, 1)
quot3 = div_numbers(10, 0) # Cannot divide by 0!
quot4 = div_numbers(10, -1)
To prevent runtime errors, code defensively and write tests for all edge cases.
NameError
What it technically means:
Python looked up a name but couldn't find it
What it practically means:
What you should look for:
Example:
fav_nut = 'pistachio'
best_chip = 'chocolate'
trail_mix = Fav_Nut + best__chip
...NoneType...
What it technically means:
You used None
(null) in some operation it wasn't meant for
What it practically means:
You forgot a return statement in a function
What you should look for:
Example:
def sum(a, b):
print(a + b)
total = sum( sum(30, 45), sum(10, 15) )
TypeError:'X' object is not callable
What it technically means:
Objects of type X cannot be treated as functions
What it practically means:
You accidentally called a non-function as if it were a function
What you should look for:
Example:
sum = 2 + 2
sum(3, 5)
When there's a runtime error in your code, you'll see a traceback in the console.
def div_numbers(dividend, divisor):
return dividend/divisor
quot1 = div_numbers(10, 2)
quot2 = div_numbers(10, 1)
quot3 = div_numbers(10, 0)
quot4 = div_numbers(10, -1)
Traceback (most recent call last):
File "main.py", line 14, in <module>
quot3 = div_numbers(10, 0)
File "main.py", line 10, in div_numbers
return dividend/divisor
ZeroDivisionError: division by zero
The most recent line of code is always last (right before the error message).
Traceback (most recent call last):
File "main.py", line 14, in <module>
quot3 = div_numbers(10, 0)
File "main.py", line 10, in div_numbers
return dividend/divisor
ZeroDivisionError: division by zero
Traceback (most recent call last):
File "main.py", line 14, in <module>
quot3 = div_numbers(10, 0)
File "main.py", line 10, in div_numbers
return dividend/divisor
ZeroDivisionError: division by zero
Python raises an exception whenever a runtime error occurs. An exception is a mechanism in many languages used to declare and respond to "exceptional" conditions.
How an exception is reported:
>>> 10/0
Traceback (most recent call last):
File "<stdin>", line 1, in
ZeroDivisionError: division by zero
If an exception is not handled, the program stops executing immediately.
To handle an exception (keep the program running), use a try
statement.
try:
<code you want to run if all goes well>
except:
<code you want to run if this particular exception happens>
...
The <try statement>
is executed first.
If and exception is raised with the <try statement>
executes,
the <except statement>
is executed.
try:
quot = 10/0
except:
print("An error happened")
quot = 0
To get the error message that Python returned, we need to catch the Exception and assign it to a variable.
try:
quot = 10/0
except Exception as e:
print('Handling an error:', e)
quot = 0
All exception types are derived from the parent class Exception
.
Exception
can be used as a wildcard that catches (almost) everythingA few exception types and examples of buggy code:
Exception | Example |
---|---|
TypeError
| 'hello'[1] = 'j'
|
IndexError
| 'hello'[7]
|
NameError
| x += 5
|
FileNotFoundError
| open('dsfdfd.txt')
|
See full list in the exceptions docs. Note: Third party Python packages often include their own custom exception types!
In some cases, we need to catch and handle specific exceptions. Multiple except statements that catch different exception types are allowed. It's a best practice to catch the default Exception, in addition to specific types.
try:
quot = 10/0
except ZeroDivisionError as e:
print('Handling zero division exception:', e)
quot = 0
except Exception as e:
print('Something else went wrong:', e)
def div_numbers(dividend, divisor):
try:
quotient = dividend/divisor
except ZeroDivisionError as e:
print('Handling zero division exception:', e)
quotient = 0
except Exception as e:
print('Something else went wrong:', e)
quotient = None
return quotient
div_numbers(10, 2)
div_numbers(10, 0)
div_numbers(10, 'foo')
Depending on the case, we may want to place the return statement inside the try statement, so that there is only a return value if the code succeeds.
To stop the program if a certain exception is encountered, move the return
statement inside the try
statement and raise a SystemExit() inside the except
statement.
def div_numbers(dividend, divisor):
try:
quotient = dividend/divisor
except ZeroDivisionError as e:
print('Encountered error:', e)
quotient = 0
except Exception as e:
print('Something else went wrong:', e)
raise SystemExit()
return quotient
div_numbers(10, 2)
div_numbers(10, 0)
div_numbers(10, -1)
Let's make our report code a bit more robust with some error handling