Python Exercises

in python

Most python exercises I found online were either too easy or tested things that were not directly related to python (mostly data structures or algorithms). Neither is a good choice when you're teaching Python courses.

This following list has helped me learn and later teach various topics in Python. They focus on the langauge itself and the standard library. Hope you'll find it useful, and feel free to add yours in comments.

Basic Syntax

  1. Write a program that asks the user for a number (integer only) and prints the sum of its digits

  2. Write a program that takes a file name as command line argument,
    count how many times each word appears in the file and prints the word that appears the most
    (and its relevant count)

Text Processing

  1. Given the following input:
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
	options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
	inet 127.0.0.1 netmask 0xff000000 
	inet6 ::1 prefixlen 128 
	inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 
	nd6 options=201<PERFORMNUD,DAD>
gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	ether f4:0f:24:29:df:4d 
	inet6 fe80::1cb5:1689:1826:cc7b%en0 prefixlen 64 secured scopeid 0x4 
	inet 10.176.85.19 netmask 0xffffff00 broadcast 10.176.85.255
	nd6 options=201<PERFORMNUD,DAD>
	media: autoselect
	status: active
en1: flags=963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX> mtu 1500
	options=60<TSO4,TSO6>
	ether 06:00:58:62:a3:00 
	media: autoselect <full-duplex>
	status: inactive
p2p0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 2304
	ether 06:0f:24:29:df:4d 
	media: autoselect
	status: inactive

Create a CSV file from the data as follows:

interface,inet,status
lo0,127.0.0.1,
gif0,,
en0,10.176.85.19,active
en1,,inactive
p2p0,,inactive   
  1. Write a python script for mass renaming music files according to labels. The script takes an existing format of files in
    current directory and an expected output format and prints a list of old -> new file name tuples.

Format can be any string that contains any number of the labels: <artist>, <album>, <track>, <year>

Assume file names match input format.

Sample list of input files:

Bob Dylan - 01 You're No Good (1962).mp3
Bob Dylan - 02 Talkin' New York (1962).mp3
Bob Dylan - 03 In My Time of Dyin' (1962).mp3
Bob Dylan - 04 Man of Constant Sorrow (1962).mp3
Bob Dylan - 05 Fixin' to Die (1962).mp3
Bob Dylan - 06 Pretty Peggy-O (1962).mp3

Sample input format:

<album> - <track> <title> (<year>).mp3

Sample output format:

Bob Dylan/<year> <album>/<track> <title>.mp3

Expected output:

Bob Dylan - 01 You're No Good (1962).mp3 -> Bob Dylan/1962 Bob Dylan/01 You're No Good.mp3
Bob Dylan - 02 Talkin' New York (1962).mp3 -> Bob Dylan/1962 Bob Dylan/02 Talkin' New York.mp3
Bob Dylan - 03 In My Time of Dyin' (1962).mp3 -> Bob Dylan/1962 Bob Dylan/03 In My Time of Dyin'.mp3
Bob Dylan - 04 Man of Constant Sorrow (1962).mp3 -> Bob Dylan/1962 Bob Dylan/04 Man of Constant Sorrow.mp3
Bob Dylan - 05 Fixin' to Die (1962).mp3 -> Bob Dylan/1962 Bob Dylan/05 Fixin' to Die.mp3
Bob Dylan - 06 Pretty Peggy-O (1962).mp3 -> Bob Dylan/1962 Bob Dylan/06 Pretty Peggy-O.mp3

Bonus: also rename the files and create required directories along the way

OS Integration

  1. Write a python program that takes a list of file extensions and prints all the files from the current
    directory matching the extension given.
    The following extensions and meaning should be supported:

    1. c should find and print all .c and .h file names
    2. py should find and print all .py and .pyc file names
    3. pl should find and print all .pl and .pm file names

Bonus: Read extension and meaning from a configuration file.

  1. Write a python program that calls ifconfig and splits its output to files according to the network interfaces it finds.

For example given the following ifconfig output:

en3: flags=8963 mtu 1500
        options=60
        ether 32:00:18:24:c0:00
        media: autoselect 
        status: inactive
p2p0: flags=8843 mtu 2304
        ether 06:38:35:47:96:24
        media: autoselect
        status: inactive

Program should create 2 files named: en3 and p2p0, saving the first block to file en3 and the second one to p2p0.

Functions

  1. Write a function that takes a number and returns the sum of its digits. Raise exception if argument of the wrong type was passed
  2. Write a function that returns the multiplication of all input arguments. The function should ignore non-numeric arguments.
    Example Usage:
# returns 200:
mymul('foo', 'bar', 10, 20)

# returns 1:
mymul()

# returns 7:
mymul(7)
  1. Write a function that takes a list of strings AND a minimum length (number) and returns only the strings that are longer than
    the provided number. Example Usage:
# returns the list: ['baby', 'more', 'time']
longer_than(3, 'hit', 'me', 'baby', 'one', 'more', 'time')
  1. Write a function groupby that takes a key-function and a list. The function should call key-function on all items in the
    list and return a dictionary whose keys are the results of key-function and values are all values from the list that
    productd that key.
    Example Usage:
# returns: { h: ['hello', 'hi', 'help', 'here'], b: ['bye'] }
groupby(lambda(s): s[0], 'hello', 'hi', 'help', 'bye', 'here')

Decorators & Generators

  1. Write a Decorator named after5 that will ignore the decorated function in the first 5 times it is called. Example Usage:
@after5
def doit(): print("Yo!")

# ignore the first 5 calls
doit()
doit()
doit()
doit()
doit()

# so only print yo once
doit()
  1. Calculation in the following fib function may take a long time. Implement a Decorator that remembers old calculations
    so the function won't calculate a fib value more than once. Program Code:
@memoize
def fib(n):
    print("fib({})".format(n))
    if n <= 2:
        return 1
    else:
        return fib(n-1) + fib(n-2)

Expected Output:

fib(10)
fib(9)
fib(8)
fib(7)
fib(6)
fib(5)
fib(4)
fib(3)
fib(2)
fib(1)
55
  1. Write a non-recursive implementation for the presented fib function using generators.

  2. Write a decorator called accepts that checks if a function was called with correct argument types. Usage example:

# make sure function can only be called with a float and an int
@accepts(float, int)
def pow(base, exp):
  pass

# raise AssertionError
pow('x', 10)
  1. Write a decorator called returns that checks that a function returns expected argument type. Usage example:
@returns(str)
def same(word)
  return word

# works:
same('hello')

# raise AssertionError:
same(10)

Classes

  1. The following code assumes a class named Widget which represent a thing that needs to be built. Building a widget
    should automatically trigger a build on all its dependencies. Implement Widget so the following code works:
luke    = Widget("Luke")
hansolo = Widget("Han Solo")
leia    = Widget("Leia")
yoda    = Widget("Yoda")
padme   = Widget("Padme Amidala")
anakin  = Widget("Anakin Skywalker")
obi     = Widget("Obi-Wan")
darth   = Widget("Darth Vader")
_all    = Widget("All")


luke.add_dependency(hansolo, leia, yoda)
leia.add_dependency(padme, anakin)
obi.add_dependency(yoda)
darth.add_dependency(anakin)

_all.add_dependency(luke, hansolo, leia, yoda, padme, anakin, obi, darth)
_all.build()
# code should print: Han Solo, Padme Amidala, Anakin Skywalker, Leia, Yoda, Luke, Obi-Wan, Darth Vader
# (can print with newlines in between modules)
  1. Provided a text file with information about artists and songs:
Joy Division - Love Will Tear Us Apart
Joy Division - New Dawn Fades
Pixies - Where Is My Mind
Pixies - Hey
Genesis - Mama

Write the required classes so the following code works:

music = MusicFile('/Users/ynonperek/music.txt')
print(music.artist('Joy Division').songs)
  1. Write a class named AddressBook that saves names and email addresses in a file. The following code should work
    (and create the file if not already exists):
with AddressBook('contacts.txt') as ab:
    ab.add('Eve', 'eve@gmail.com')
    ab.add('Alice', 'alice@walla.co.il')

with AddressBook('contacts.txt') as ab:
    print(ab.email('Eve'))
  1. Modify the class so the following will also work (Hint: read about __getitem__):
with AddressBook('contacts.txt') as ab:
    print(ab['Eve'])

Modules

  1. Provided test file test_stack.py. Write the module required to make the test pass:
import unittest
from lib import mystack

class TestMyStack(unittest.TestCase):
    def setUp(self):
        mystack.add_item(10);
        mystack.add_item(20);
        mystack.add_item(22, 33);

    def test_flow(self):
        self.assertEqual(mystack.pop_item(), 33)
        self.assertEqual(mystack.pop_item(), 22)
        self.assertEqual(mystack.count_items(), 2)
        while mystack.pop_item(): pass

        self.assertEqual(mystack.count_items(), 0)
  1. Provided the test file test_contacts.py. Write the module required to make the test pass:
import unittest
from lib.contacts import Contacts

class TestContacts(unittest.TestCase):
    def setUp(self):
        self.home_book = Contacts()
        self.work_book = Contacts()

    def test_create_and_search(self):
        self.home_book.add('Tom', { 'lives_in': 'USA', 'email': 'tomthecat@gmail.com' })
        self.home_book.add('Bob', { 'lives_in': 'USA', 'email': 'bob@gmail.com' })
        self.work_book.add('Mike', { 'lives_in': 'Marks', 'email': 'mike@gmail.com' })

        results = self.home_book.contacts_by_lives_in('USA')
        self.assertTrue('Tom' in results)
        self.assertTrue('Bob' in results)
        self.assertEqual(len(results), 2)
  1. Write a module for finding anagrams in a list of words. Two words are an anagram if they have the same letters, for example
    add and dad are an anagram. The module should provide a class named Anagramer with the methods:

    • __init__(wordsfile) takes a words file and parses it to an anagram repository
    • get_random_anagram that returns a random anagram from the repository
    • list_anagrams(word) that lists all anagrams for a given word
  2. Write unit tests to test Anagramer.

Exceptions

  1. Write a program that takes a file name from command line and prints the number of lines in that file. If the provided argument
    does not refer to a file an error should be printed. Example Usage:
python countlines.py /etc/shells
11

python countlines.py /foo/bar
Sorry, file /foo/bar not found
  1. The following code assumes a class named ImageFile exists. Implement that class so the test passes:
import unittest

class TestImageFile(unittest.TestCase):
    def test_good_ext(self):
        try:
            img = ImageFile("file.png")
        except InvalidImageExt:
            self.fail("png should be a valid file extension")

    def test_bad_ext(self):
        with self.assertRaises(InvalidImageExt):
            img = ImageFile("file.mp3")

unittest.main()
  1. Write a function named readtype that takes a type and reads data from the user until data of the given type is found.
    Example Usage:
x = readtype(int)
print(x)

t = readtype(str, prompt='Who are you? ')
print(t)

Lists & Dictionaries

  1. Write the class AddressBook so the following code works:
c = AddressBook()

c.add(name='ynon', email='ynon@ynonperek.com', likes='red')
c.add(name='bob', email='bob@gmail.com', likes='blue')
c.add(name='ynon', email='ynon@gmail.com', likes='blue')

c.find_by(name='ynon')
# returns:
# [
#   {'name': 'ynon', 'email': 'ynon@ynonperek.com', 'likes': 'red'},
#   {'name': 'ynon', 'email': 'ynon@gmail.com', 'likes': 'blue}
# ]

c.find_by(likes='blue)
# returns:
# [
#   { 'name': 'bob', 'email': 'bob@gmail.com', 'likes': 'blue' },
#   {'name': 'ynon', 'email': 'ynon@gmail.com', 'likes': 'blue}
# ]

Code should be generic enough so if new fields are added everything still works.

  1. The following code should have created a triplet of blank squares for a tic-tac-toe game, but it has a strange bug. What
    went wrong and how would you fix it?
BLANK = ['', '', '']
g = [BLANK] * 3
g[0][0] = 'x'

Multiprocessing

  1. Provided the following passwords.md5 file that contains md5 hashed passwords. Write a python program that finds as many
    original passwords as you can. Can you speed it up using multiple processes? What's the ideal number of processes to use?

  2. Read documentation on Manager and afterwards update the program so after finding a password it'll also print how many
    passwords are left to search.

passwords.md5 file:

e10adc3949ba59abbe56e057f20f883e
5f4dcc3b5aa765d61d8327deb882cf99
827ccb0eea8a706c4c34a16891f84e7b
25d55ad283aa400af464c76d713c07ad
d8578edf8458ce06fbc5bb76a58c5ca4
9cdda062c5bd8e38e3a576c61208e1d4
25f9e794323b453885f5181f1b624d0b
81dc9bdb52d04dc20036dbd8313ed055
276f8db0b86edaa7fc805516c852c889
8621ffdbc5698829397d97767ac13db3
37b4e2d82900d5e94b8da524fbeb33c0
fcea920f7412b5da7be0cf42b8c93759
d0763edaa9d9bd2a9516280e9044d885
0d107d09f5bbe40cade3de5c71e9e9b7
8c62573d0982c91aad72e634ed6903f2
e99a18c428cb38d5f260853678922e03
96e79218965eb72c92a549dd5a330112
bee783ee2974595487357e195ef38ca2
d5bb5c0168e2952b6806d6a976b3d98a
9df3b01c60df20d13843841ff0d4482c
3bf1114a986ba87ed28fc1b5884fc2f8
eb0a191797624dd3a48fa681d3061212
c3add14b93c46349dfcb10e2d1c311a0
0acf4539a14b3aa27deeb4cbdf6e989f
84d961568a65073a3bcf0eb216b2a576
7d0710824ff191f6a0086a7e3891641e
e6c25c740b384de04637269b7715e067
4297f44b13955235245b2497399d7a93
ec0e2603172c73a8b644bb9456c1ff6e
5fcfd41e547a12215b173ff47fdd3739
  1. What's the problem in the following code? Fix it!
import multiprocessing
import random

words = ['I', 'can', 'see', 'the', 'mountains']

def write_word_to_file(f):
    w = random.choice(words)
    f.write("{}\n".format(w))

def run(fl, n):
    for _ in range(n):
        write_word_to_file(fl)

q = multiprocessing.Pool()
f = open('out.txt', 'a')

procs = [ multiprocessing.Process(target=run, args=(f,5)) for _ in range(5) ]
for p in procs: p.start()
for p in procs: p.join()

f.close()
  1. Write a program that calculates all prime numbers from 1 to 100_000 and writes them to a file (not necessarily in order):
  • First use a single process
  • Then modify to use multiple processes, each writes to the file on its own
  • Finally modify to use a Queue where many processes find prime numbers, but only one process writes the results to a file.

Which option came out the fastest?

Unit Tests

  1. Given the following class:
class File:
    def __init__(self, name):
        self.path = name

    def create(self):
        open(self.path, 'a').close()

    def rename(self, new_name):
        os.rename(self.path, new_name)
        self.path = new_name

Write test case to verify:

  • can create files
  • can rename files
  • exception is raised when trying to create files without permissions
  • exception is raised when trying to rename a directory using this class

Fix the code if needed to make all tests pass.

  1. Given the mass renamer you wrote in Regular Expression exercise, write test code to verify:
  • Described functionality in the exercise (Regexp Part 4) works
  • Can rename files that have different name format
  • Code raises an exception if output format includes a label that does not appear in input format
  1. Given the following code:
import requests

def download(url, filename):
    r = requests.get(url, stream=True)
    if r.status_code == 200:
        with open(filename, 'wb') as f:
            for chunk in r:
                f.write(chunk)
    else:
        raise Exception(r.reason)


if __name__ == '__main__':
    url = 'https://fthmb.tqn.com/fgT8_8SUVjRLrOKMJp7OBD7R30o=/3372x2248/filters:fill(auto,1)/about/kitten-looking-at-camera-521981437-57d840213df78c583374be3b.jpg'
    download(url, 'kitten.jpg')

Write unit tests to:

  • verify code raises an exception when download fails
  • verify code writes content to file when download succeeds

Unit test code should not cause any network activity (i.e. should work offline).

  1. The following class randomizes a number and allows the user to guess what the number is:
import random

class NumberGuessingGame:
    def __init__(self):
        self._value = self.get_new_number()

    def guess(self, guess):
        if guess < self._value:
            print('too low')
        elif guess > self._value:
            print('too high')
        else:
            print('Bravo!')

    def get_new_number(self):
        return random.randint(1,1000)

Write unit test code to:

  • verify code writes "too low" when guess is below selected number
  • verify code writes "too high" when guess is above selected number
  • verify code write "Bravo!" when guess is exactly selected number

Modify the original class if you feel it can improve the tests.

Comments