Basic - Python Fall 2026
- Submission Instructions
- Preface
- Ramping up
- Jotting things down
- “Fun” is in “function”
- Classes
- The filesystem
- Some extras
- Conclusion
Submission Instructions
This homework will be submitted as a repository on the EECS GitLab
server. The repository you submit will be a private Project with
the name/path eecs201-basic-python with akamil added as a Reporter. The branch rel
will be the one that is checked.
To finish the submission process and get your submission score, you will need to run the autograder. You will need to SSH into the course server (see Basic - Intro):
local$ ssh uniqname@peritia.eecs.umich.edu
(the local$
referring to a shell prompt on your system)
and then run eecs201-test:
peritia$ eecs201-test basic-python
(the peritia$
referring to a shell prompt on the server)
Preface
For this assignment you’re going to need Python 3. The package name
for it on Ubuntu is
python3 (the “normal”
python package might
be for Python 2.7, depending on your version of Ubuntu). Otherwise,
there’s various ways you can install it: look it up for your given
platform if you aren’t using WSL+Ubuntu. Go ahead and install it on your
system if you wish to do this assignment locally.
In this assignment you’ll be provided yet another zipped archive containing some starter files.
https://www.eecs.umich.edu/courses/eecs201/fa2026/files/assignments/basic-python.tar.gz
Note that this assignment is to be submitted on a remote branch called
rel. Initialize a Git
repository inside of the extracted
basic-python
directory; as noted above
git init -b <branch name>
or
git init --initial-branch <branch name>
can initialize the repo with a different branch name (e.g.
rel as per the
submission instructions). If your version of Git is too old for these
options, you could create the
rel branch afterwards
after your first commit, or you can set the local branch’s tracking
information manually. Create a file called
report.txt in this
directory.
Add all of the present files and commit them.
Create a private project named
eecs201-basic-python
on the EECS GitLab
(gitlab.eecs.umich.edu)
and add the instructor
akamil as a
Reporter. Set this UMich GitLab project as your remote: you’ll be
pushing to it in order to submit.
Ramping up
In this section you’ll be getting familiar with forming Python expressions. This section has no submission component and is purely for exploring the syntax. If you are already familiar with Python, you may skip this section.
-
First we’re going to work in Python’s interactive shell. Run
$ python3(or$ pythonif your system’s default Python is Python 3). -
In the interactive shell, much like MATLAB if you have used that, the value of the result of an entered expression will be printed out (remember from lecture that expressions can be statements!).
-
>>>will be used to indicate Python interactive shell prompts. -
Run
>>> 6 * 7. This will multiply 6 with 7. -
Run
>>> "Hello " + "world!". This will produce a newstrthat concatenates the two. -
Run
>>> len("Hello"). This is an example of the built-in functionlen()being used on astr, which is a sequence. -
Messing around with types is cool, but let’s now save the values we create.
-
Run
>>> x = 6 * 7. We are now binding variable/identifierxto anintobject of value 42 (i.e.xequals 42). -
We can print out an object as well (provided it has implemented a
__str__function, which the built-in types have). Run>>> print(x). -
We can get information about the object
xis bound to. Run>>> type(x): this gets type of the object bound tox. -
Run
>>> id(x): this gets the ID of the object bound tox. -
Let’s use
xin an expression. Run>>> y = x - 42. Print outy. -
Run
>>> z = "Hello world!" -
Run
>>> print(z). Here’s our obligatory “Hello world!” -
Let’s now play with another built-in type: the list. Run
>>> l = [x, y, z]. This will construct a list using the objects bound by x, y, and z. Note how we can stuff arbitrary objects into a list! -
Run
>>> print(l). As mentioned before, the built-in types can be nicely printed. -
A list can be indexed by an integer position: run
>>> print(l[0]) -
Let’s check if the objects referred to by
xandl[0]are the same: run>>> x is l[0]. This performs an ID check between the two objects referred to byxandl[0]and returns a boolean (alternatively,>>> id(x) == id(l[0])works as well). -
Try verifying that
yandzare the same asl[1]andl[2]. -
Let’s manipulate this list (lists are mutable after all). Run
>>> l.append(3.14). Try printing outlagain. Withappend()we have added afloatto listl. -
Lastly, let’s play with dictionaries. Initialize an empty dictionary with
>>> dictionary = {}. -
Let’s set the key-value pairs “foo”=0 and “bar”=1:
>>> dictionary[’foo’]=0>>> dictionary[’bar’]=1 -
Let’s retrieve the values associated with the keys:
>>> print(dictionary[’foo’]>>> print(dictionary[’bar’] -
To quit the interactive shell, run
>>> quit()or, like in most other shells, send an EOF (end-of-file) by hitting Ctrl-D (D)
If you had 0 experience with Python going in, hopefully this small intro put you more at ease: Python has a fairly simple syntax, free from a lot of cruft. While it can serve as a scripting language, it definitely is a lot more familiar and intuitive compared to something like Bash.
Jotting things down
Much like Bash, we can put statements in at the interactive shell or we can put down our statements in a script to be run at our convenience.
-
Create a file named
loops.py -
If you want to, put:
#!/usr/bin/env python3. This shebang will use theenvexecutable to findpython3and use that as the interpreter if you decide to execute the file directly afterchmoding it. I’m going to explicitly run these scripts underpython3, so you don’t actually have to do this step. -
In the script,
importthesysmodule. This module provides info about the current interpreter, such as the command-line arguments. -
sys.argvis a list of command-line arguments provided to the script. Like many programming languages, the list contains the script file’s name as the 0th argument. -
Add a check to see that at least one additional command-line argument was added. Note that you can call
len()on a list to get its length. Note that the 0th argument counts towards this length:$ python3 loops.pyor$ ./loops.pywill both have an argument list of['./loops.py']and a length of 1.If there isn’t, exit with a status code of 1 via
exit()orsys.exit(). -
The 1st argument will serve as an integer: assign a variable to be that integer value. The built-in
int()function is able to perform conversions of various types to integer. -
In the script, add a
while-loop toprint()out the integers from 1 to the script’s command-line argument. -
Add a
for-loop withrange()toprint()out the integers from 1 to the script’s command-line argument. -
Try running
$ python3 loops.py 10. As a result of both loops, you should see 1 to 10 be printed out with each number on its own line, then 1 to 10 printed out again.
“Fun” is in “function”
We’ll now play around with functions. Much like in Bash, functions can be declared and then called, albeit the calling syntax is a lot more familiar. For you folk who are used to Python, feel free to take full advantage of some of the more Pythonic expressions (like comprehensions) for these ;)
-
Create a file named
functions.py. This file will contain some functions that can be called from elsewhere. -
Create and implement a function called
lower_listthat takes in a string (str) a returns a list of the string’s characters that are lowercase, in the order that they were in from the string (and with duplicates if the same letter comes up multiple times). For example,lower_list("HelLo")returns[’e’, ’l’, ’o’]. Note that there is astrfunction calledislower(). -
Create and implement a function called
list_to_string_dictthat takes in alistoftuplesrepresenting key-value pairs where the 0th element is a key and the 1st element is a value (beyond being an immutable sequence, tuples, like in some other languages, are often used to act as an object with unnamed variables). The function returns adictmade up of the key-value pairs in the input list that have keys that are strings. For example,list_to_string_dict([(’hello’, 1), (’world’, 42), (1234, 5)])would return adictthat is representable by{’hello’:1, ’world’:42}. You can handle this by getting thetype()of that object and checking if itisastr. -
You can use the provided
test-functions.pyfile to test out your functions (you’ll have to write the code to do this; the file only contains some boilerplate). Note that depending on the way the file is imported, you may have to navigate the namespace e.g.functions.lower_list. The waytest-functions.pyimports it will allow you to just calllower_listandlist_to_string_dict. You can also try them out in the interpreter shell by importing it :) -
Since this file is meant to contain functions that will be called elsewhere (e.g. be imported), it’s kind of poor form to simply add statements that call the functions at the bottom of the file: when files are imported, each line is run, and we wouldn’t want to call these functions when someone else wants to import this file.
-
Another option can be to create an if-block in
functions.pythat saysif __name__ == '__main__':and put your testing statements in there. How this works is when you run a script as the main program (e.g. via the command line), a special variable called__name__is assigned to the string'__main__', allowing you to differentiate between when this script is being run from the command line or is being imported. There’s some neat use cases of this: for instance you could write a script that’s mostly meant to be run as a program, but offers an API (application-programming-interface) for more advanced users to take advantage of, or you could write a library intended to be imported but have the script run some test cases or a reference program when run.
Classes
Python also is object-oriented: so much so that everything is an object. We can define our own classes as well!
-
Create a file named
classes.py. This file will contain some classes that will be usable from elsewhere. -
Define a
Studentclass whose instances are composed of the member variablesname(str) andgrade(float). The__init__()function should, after the object instance argument (e.g.self), have the argumentsnameandgradein that order. -
Add a method to
Studentcalledpassing()that returnsTrueif theirgradeis greater than or equal to70.0andFalseif their grade is less than70.0. -
There are also methods that you can define for your class that’ll interface with some built-in functions like
str(). Forstr()to work on your class, you’ll have to implement the__str__()function (a so-called “dunder method”). Implement it so that when you callstr()on aStudent, it will return<Name> - <Grade>e.g.Bob - 84. Mind the space around the-! There’s multiple ways to do this, such as appending strings together or using theformat()function. Try runningprint()on aStudentnow :)On a sidenote, there’s also
__repr__()for “formal” string representations of a class. This StackOverflow post has a nice summary. -
You can use the provided
test-classes.pyfile to test out your functions. You can also try them out in the interpreter shell or via theif __name__from before.
The filesystem
Things aren’t as interesting when we can’t interact with anything.
-
Create a file named
files.py. -
In this script open the file named
data.txtfor reading. Try using thewith...as...mechanism. If you go for the plain-oldopen()...close()paradigm, don’t forget to close the file at the end. -
Read and print out each line in the file. The
readline()andreadlines()functions may be helpful. Also note that you can iterate over a file with afor-loop. -
Make sure that you don’t double-print newlines: the
strip()function forstrobjects that gets rid of whitespace at the beginning and end of a string may help out here.
Some extras
This section will be more for exploring things. No submission for these, but they’re some things to keep in mind.
Running other commands
There’s two relatively easy ways to run some other program or command
from Python. From the
os module we have
os.system(), which
allows you to shell commands (i.e. the C
system() function).
For example:
os.system("ls -ltr somedir").
The downside is that there isn’t a way to capture the output with this.
The subprocess
module, however, has a rich set of utilities for this purpose. The
subprocess.run()
function is a high level function that allows you to run commands,
capture their outputs, and check their statuses. For example:
subprocess.run([’ls’, ’-ltr’, ’somedir’], capture_output=True)
will run the command specified by a list of arguments as well as
capturing the output for the returned object. The object it returns is a
CompletedObject which
has a stdout
attribute that is a
bytes containing the
output of the command. This
bytes can then be
encoded (e.g. via UTF-8) to give you a
str.
Putting it together:
subprocess.run([’ls’, ’-ltr’, ’somedir’], capture_output=True).stdout.encode(’utf-8’)
Alternatively, you can provide an encoding to
subprocess.run. Try
looking at the documentation for more details :)
With the power of being able to call other utilities on your system you might find Python a really neat way to automate lots of stuff :)
Being Pythonic with comprehensions
A word that comes up often is “Pythonic”: this refers to the taking
advantage of features and things built into Python that help clean up
and express ideas that would otherwise be messier in other languages due
to some quirk of syntax. For instance, you may be used to using an
iterating index variable in C/C++ to index into an array, but the
“Pythonic” way would be to just directly iterate over it. Sure, you
could do
for i in range(len(somelist)):,
but unless you absolutely need an integer index for something, why not
express it as
for item in somelist:?
One of the neat features of Python that we brought up in lecture are
“comprehensions”. They allow you to easily build things like lists,
sets, and dictionaries with iterable objects. For instance, if I wanted
to get a list of the grades squared from a list of
Students named
students:
grades = [student.grade ** 2 for student in students]
or maybe you want the names of students who are passing:
passing_students = [student.name for student in students if student.passing()]
Dictionaries have a similar syntax. Perhaps you have a dictionary but want to keep only pairs whose keys are strings:
only_strings = {k:v for k,v in somedict.items() if type(k) is str}
Try tackling #2 using comprehensions!
Conclusion
-
Add and commit the files you created.
-
Fill out the
report.txtfile in the following steps: -
On the first line provide an integer time in minutes of how long it took for you to complete this assignment. It should just be an integer: no letters or words.
-
On the second line and beyond, write down what you learned while doing this assignment. If you already knew how to do all of this, put down “N/A”.
-
Commit your
report.txtfile and push your commits to your remote. -
Try running
eecs201-teston this assignment on the course server! If you don’t remember, check out the last part of Basic - Git.