Flashcards Project
Contents
Flashcards Project#
This is the project to apply what we’ve learned in the Files lessons.
The project is to write a program for running through flashcards. Card data is
stored in csv
files in the data/flashcards
directory.
Instructions#
Table of Contents
Part 1: Make a csv
file#
The flashcards data will be stored in csv
files in a directory named
data/flashcards
. The idea is to eventually have multiple files for different
topics that you might want to study like paths.csv
, functions.csv
and so
on. For now though, just make one file.
[ ]
Create a folderdata/flashcards
if it doesn’t already exist[ ]
Make acsv
file with flashcard data[ ]
In thedata/flashcards
directory manually make file ending in.csv
. For examplepaths.csv
.[ ]
Each line should be one card with the format:text for front, text for back
.
For example:front, back import the Path class, from pathlib import Path check if Path object path exists, path.exists() check if Path object path is a file, path.is_file() check if Path object path is a directory, path.is_dir()
Part 2: Start flashcards.py
#
Start your flashcards.py
file.
[ ]
write amain()
function[ ]
print any temporary debug message in it[ ]
call it
Part 3: Start load_csv()
#
The load_csv()
function should take one argument, a Path
object to a csv
file. Eventually it will return a list
where each item is a dict
with "front"
and "back"
keys, one for each row in the file except the header.
For now though, make a simple function that just takes a Path
object, prints
the location, and makes sure the file exists.
load_csv()
[ ]
write aload_csv()
function that takes one argument:path
[ ]
check to make sure thecsv
file exists. If not, print an error message that includes the path then return[ ]
print a temporary debug message:loading file: path
in main()
[ ]
make aPath
object to yourcsv
file[ ]
call yourload_csv()
function, passing it yourPath
object as the argument, and assign the returned value to a variable namedcards
Part 4: Read each line of the csv file#
Expand the load_csv()
function to read and print every line in the file.
in load_csv()
[ ]
open the csv file in read mode using theopen()
function[ ]
usefh.readlines()
to iterate through each line in the file[ ]
for temporary debugging, print each line
Part 5: Get the card data from the csv file#
Continue expanding the load_csv()
function to extract the card data from each
line, put it into a dictionary named cards
with the keys "front"
and
"back"
.
in load_csv(), in the readlines() loop
[ ]
make an emptydict
assigned to a variable namedcard
[ ]
split each line on the","
using the.split()
method and assign the result to a variable namedrow
[ ]
check that there are two items in the row using thelen()
function. If not print an error message and return[ ]
assigncard["front"]
to the first item in the row, andcard["back"]
to the second[ ]
for temporary debugging, print thecard
dict
Part 6: Return the card data to main()
#
Have load_csv()
put all of the card
dictionaries into one big cards
list
and return that to main()
.
in load_csv(), before the readlines() loop
[ ]
make an emptylist
assigned to a variable namedcards
in load_csv(), at the end of the readlines() loop
[ ]
use the.append()
method on thecards
list
with the argumentcard
in load_csv(), after the loop
[ ]
returncards
in main()
[ ]
if thecards
list
is falsy,return
[ ]
otherwise, print thecards
list
for temporary debugging
Part 7: Remove extra whitespace#
In order to make sure that the flashcards are printed nicely and that the users
answers get matched up correctly, the trailing "\n"
needs to be removed from
the end of each line. Any extra spaces that happen to be around the ","
or at
the beginning or end of the line also need to be removed.
in load_csv(), in the loop
[ ]
remove leading and trailing whitespace by calling the.strip()
method oncard["front"]
andcard["back"]
part 8: Skip the header row and blank lines#
To avoid having a flashcard pop up that reads "front"
, don’t append the
header row to the cards
list
. Also skip any blank lines in the file.
in load_csv(), in the readlines() loop, before append
[ ]
check ifcard["front"]
is"front"
andcard["back"]
is"back"
. If so,continue
to avoid appending to the cards list[ ]
check ifline
is equal to"\n"
. If so,continue
.
Part 9: Start the play()
function#
This function should take one argument, the list of cards. Eventually it will contain the user interface for running through each card, getting the answers from the user, and printing the score.
For now ‘ll just write a play()
function and call it.
play()
[ ]
write aplay() f
unction that takes one argument:cards
[ ]
for temporary debugging, print something from it
main()
[ ]
callplay()
passing it the list ofcards
Part 10: Go through each card in random order#
In this next part we’ll be metaphorically drawing a card at random from the deck until there are none left.
The trick is to make a while loop that checks the truthy value
of cards
, so that it stops as soon as its empty. The inside the loop, use the
random.choice()
method to pick a card
at random, then remove it from the list.
at the top of your file
[ ]
import
therandom
module
in play()
[ ]
make a while loop where the condition is:cards
in play(), in the loop
[ ]
userandom.choice()
to get a random item from thecards
list and assign it to a variable namedcard
[ ]
call the.remove()
method oncards
with the argumentcard
to remove the card from the list[ ]
for temporary debugging, printcard
Part 11: Test the user#
This is where things start to get exciting! In this part we’ll print the front of the card, ask the user for their answer, and let them know if it was right or not.
in play(), in the loop
[ ]
printcard["front"]
[ ]
prompt the user for their answer using theinput()
function and assign the result to a variable namedanswer
[ ]
check if theanswer
is the same ascard["back"]
[ ]
if so, print"CORRECT"
[ ]
if not, print"INCORRECT",
thencards["back"]
[ ]
callinput()
asking if the user wants to continue[ ]
if not, return
in play(), after the loop
Part 12: Scorekeeping#
Now lets keep track of which card the user is on, and what their score is.
in play(), above the loop
[ ]
make ascore
variable set to0
[ ]
assign the length of cards to a variabletotal
[ ]
make anum
variable set to1
in play(), in the loop
[ ]
at the top of the loop printcard num of total
[ ]
when you check if theanswer
is the same ascard["back"]
[ ]
if so, incrementscore
by one
[ ]
at the end of the loop, incrementnum
by1
in play(), after the loop
[ ]
print"score of total"
Part 13: Prettify flashcards#
This part is about making the flashcards look nicer. Feel free to adjust these suggestions to your taste.
throughout your file
[ ]
get rid of any debugprint()
statements
at the top of your file
[ ]
make a global variableWIDTH
and set it to around75
in play()
[ ]
print a line to the beginning and end of each card[ ]
add some extra newlines around various elements[ ]
center any string by calling the.center()
method on it and pass the argumentWIDTH
. For example, thecard["front"]
line.[ ]
right align any string by calling the .rjust() method on it and passing the argumentWIDTH
. For example, thecard x of y
line.[ ]
print"score of total"
after the end of each card
Part 14: Wrap long questions#
In this part wrap questions that are too long so that they are split into multiple lines.
at the top of your file
[ ]
If you want your questions to be wrap at a shorter length thanWIDTH
, set aMAXWIDTH
global variable.[ ]
import
thetextwrap
module
in play(), in the loop
[ ]
Calltextwrap.wrap()
with the argumentscard["front"]
and the width you want to wrap at, eitherMAXWIDTH
orWIDTH
. This will return alist
of strings, where each item is a line. Assign the results to a variablelines
.[ ]
Remove the code that printscard["front"]
[ ]
Iterate over thelines
list, and print each item.
Part 16: Allow answers with commas#
Many answers have commas in them, so instead of manually parsing the csv file,
lets use the built in csv
module.
We’ll create and iterate over a csv.reader
object, which will provide each
line split into a list of fields that we can use as the row
. Then either
remove all of the places where we use line
, or replace them with an
equivalent for row
.
at the top of your file
[ ]
import
thecsv
module
in load_csv() after opening your file
[ ]
Create a new csv reader like so:reader = csv.reader( fh, quotechar="'", skipinitialspace=True, escapechar="\\" )
[ ]
Instead of iterating overfh.readlines()
, iterate over thereader
object. Change the variable name in the for loop torow
.
in load_csv(), in the for loop
[ ]
Remove therow = line.split()
line. (Sincerow
is now a list provided by thereader
object.)[ ]
Check ifrow
is an empty list. If so,continue
.
Part 17: limit CLI argument#
In this section we’ll change the program to accept an optional command line argument to limit the number of cards to show.
So, if at the command line you type:
$ python flashcards.py 10
Then at most 10 flashcards will be shown.
Or if you type:
$ python flashcards.py
Then then you’ll go through all of the flashcards for the selected topic(s).
In the main() function, before calling play():
[ ]
Check ifsys.argv
has more than1
item. If so:[ ]
assign the second value in thesys.argv
list, converted to anint
to the variablelimit
[ ]
get a slice of thecards
list with a size equal tolimit
and assign it back to the variablecards
Bonus ideas#
keep a log with dates and scores
print any cards that the user got wrong again at the end after showing the score
Card data#
Download the following flashcard files or feel free to make your own.
Screencasts#
Reference#
You can view my completed scripts here: