Advanced Python
In-Class Exercises, Session 2

COMMAND LINE AND ZIP FILE

Ex. 2.1 Open a Anaconda Prompt (Windows) or a Terminal window (Mac). (To reach the Anaconda prompt, do a search for Anaconda and click Anaconad Prompt.)

  • (Unix only) Use pwd to see the "present working directory"
  • Use ls (Mac) or dir (Windows) to see a listing of the files and directories in this directory
  • Use cd to move into a directory you see listed in the present working directory (for example cd Downloads)
  • Use cd .. to move into the "parent" directory of the one you are in (this will take you back to the parent of Downlaods
  • Use cd /Users/[yourhomedir]/Desktop to move into the Desktop directory
  • Use cd ../Downloads to move from the Desktop directory to the Downloads directory
  • Use cd (Mac) or cd %HOMEPATH% (Windows) to move back into the home directory

 

SQLITE COMMANDS

Ex. 2.2 In the Anaconda Prompt (Windows) or a Terminal window (Mac), travel to the project directory (look at the prompt (Windows) or use pwd (Mac) to see where you are (the present working directory); ls (Mac) or dir (Windows) to see what is in the present directory, and cd [dirname] to travel to a directory, or cd .. to travel into the parent directory. Launch sqlite with the command sqlite3.


If you unzipped your project directory in the Downloads folder, the commands are:

Mac:
cd
cd Downloads
cd python_data
cd session_02_files
Windows:
cd %HOMEPATH%
cd Downloads
cd python_data
cd session_02_files

If any command returns an error, check the spelling of your command. If the 3rd command returns an error, check that the session_02_files folder was unzipped to your Downloads directory (and that you've spelled it correctly).

start sqlite:
sqlite3
You should see the sqlite prompt:
sqlite>
You can quit out of sqlite with .quit:
sqlite>  .quit
 
Ex. 2.3 Open a database file, then immediately check to see that there are tables.
From the sqlite prompt:
sqlite> .open session_2.db
sqlite> .tables
ad_buys              revenue              students
ad_companies         student_status       user
companyrev           student_status_orig  user_classes

If you don't see any tables listed, then you have either misspelled the name of the .db file, or you're in the wrong directory. First, delete the empty file that you created so you don't get confused.

See the present working directory on Windows:
sqlite> .shell cd
See the present working directory on Mac:
sqlite> .shell pwd

You can use .shell commands to move into the directory where the .db file can be found.
Please note that SQL queries end in a semicolon (;) and SQLite3 commands such as .tables and .schema do not: adding a semicolon to a "dot" command (e.g. .schema;) causes SQLite to ignore the command; omitting a semicolon from a query causes SQLite to allow "multi-line" queries, which means it will wait until it sees the semicolon.

 
Ex. 2.4 Set display columns. This configures SQLite to show SELECT output in columns with headers.
sqlite> .header on
sqlite> .mode column
 
Ex. 2.5 Show the schema for a table. Use the .schema command to see the CREATE TABLE for the revenue table, which shows its structure.
show schema for a table:
sqlite> .schema revenue
 

SQL COMMANDS

Ex. 2.6 Select all rows from the revenue table.
sqlite> SELECT * FROM revenue;

Please note that SQL queries end in a semicolon (;) and SQLite3 commands such as .tables and .schema do not: adding a semicolon to a "dot" command (e.g. .schema; causes SQLite to ignore the command; omitting a semicolon from a query causes SQLite to allow "multi-line" queries, which means it will wait until it sees the semicolon. If you see a continuation line indicator ( ...> ) this means that you have started an SQL client and the client is waiting for more SQL (queries can be expressed in more than one line, so the client needs the semicolon to understand the end of the query). If you're done, simply type the semicolon and hit [Enter].

 
Ex. 2.7 Create a new table called 'test', with columns 'name' (a TEXT column), 'years' (INT) and 'revenue' (a REAL (or floating-point) column). Use the .schema to verify the table's existence and have the query echoed back to you.
sqlite> CREATE TABLE test (name TEXT, years INT, revenue REAL);
sqlite> .schema test
CREATE TABLE test (name TEXT, years INT, revenue REAL);
 
Ex. 2.8 Drop the table you just created.
sqlite> DROP TABLE test;
 
Ex. 2.9 Recreate the table test by using the up arrow to retrieve the original CREATE TABLE statement. (Make sure not to retype the CREATE TABLE statement - you don't need to!)
Use the up arrow (twice) on the SQLite3 client, no need to retype:
sqlite> CREATE TABLE test (name TEXT, years INT, revenue REAL);
 
Ex. 2.10 Insert a row into the test table. Run the query a few times by pressing the up arrow and hitting [Enter]
sqlite> INSERT INTO test VALUES ('Joe', 23, 23.95);

Note that TEXT column values must have quotes around them and INT and REAL (floating-point) column values must not.

 
Ex. 2.11 Run a select query to display the rows you inserted.
sqlite> SELECT * FROM test;
 
Ex. 2.12 Delete all rows from the table.
sqlite> DELETE FROM test;
 
Ex. 2.13 Drop table entirely.
sqlite> DROP TABLE test;
 
Ex. 2.14 Note that you can't drop a nonexistent table. Attempt to drop the 'test' table again, and note that this fails. Add an IF EXISTS so that if the table exists, it will be dropped; if it does not exist, it will return an error. This is especially useful for the "wipe and reload" best practice.

Next, use the up arrow to recover and re-execute the CREATE TABLE and follow it up imediately with the DROP TABLE IF EXISTS -- to see how easy it is to create and drop tables.

sqlite> DROP TABLE IF EXISTS test;
sqlite> CREATE TABLE test (name TEXT, years INT, revenue REAL);
sqlite> DROP TABLE IF EXISTS test;
sqlite> CREATE TABLE test (name TEXT, years INT, revenue REAL);

Remember, you don't have to retype an old command! Just use up arrow and down arrow to recall previously executed commands.

 

Please KEEP YOUR SQLite SESSION OPEN FOR THE FOLLOWING Python exercises.

LAB 1

Note: if this is a new session, please follow the directions at the start of these exercises and the first few exercises to travel to the directory where session_2.db can be found, to verify that it is in your current location, and to use .open to open the file. (Don't forget that if you are in the wrong location or misspell the filename you will create a new, empty database file.)

Also in a new session, always remember to issue the setup commands:
.mode column
.headers on
Ex. 2.15 Issue a .tables command to verify that you have opened the existing session_2.db file:
.tables
Expected Output:
ad_buys         companyrev      student_status  user
ad_companies    revenue         students        user_classes

(please note that your table listing may be different than shown above, but should at least show several tables rather than no tables) If there are no tables listed, use .quit to leave sqlite3, use ls or dir to see that you have created a new, empty .db file (you can check the size in your Windows Explorer or Mac Finder view of the file), and then delete this file. Then return to the start of these exercises and follow directions to find the existing session_2.db file.

 
Ex. 2.16 CREATE TABLE from database prompt.
Create a table called planets with the following columns:
planet (a TEXT field)
mass (a REAL (or floating-point) field)
distance (an INT field)

When done, issue a .schema query to see the query and structure of the table reflected back to you.

 
Ex. 2.17 INSERT query from database prompt.
Insert each of the following rows of values into the planets table by executing 3 separate INSERT query statements:
Mercury   .33    58
Venus    4.87   108
Earth    5.98   150

The sqlite prompt should return without error after each INSERT query.

 
Ex. 2.18 SELECT query from database prompt.

Select all rows and columns from the planets table.

Expected Output:
planet      mass        distance
----------  ----------  ----------
Mercury     0.33        58
Venus       4.87        108
Earth       5.98        150
 
Ex. 2.19 SELECT query for specific columns with WHERE clause from database prompt.

Select the planet and and distance columns for all planets further than 100 (km) from the sun.

Expected Output:
planet      distance
----------  ----------
Venus       108
Earth       150
 

Please keep this sqlite session open, or make note of where your session_2.db file is located so we can access the data you created in the next lab.

DATABASE ACCESS FROM PYTHON

NOTE THAT when opening data files from the exercise files or notebooks, any filename referenced from those exercises should be preceded with ../. (If you create a script in the same directory as the data file, you would not include this.) NOTE ALSO THAT if you are using Jupyter Notebook, if you wish to call exit() from a notebook, please use sys.exit() (requires import sys); if a strange error occurs, it may be because Jupyter retains variables from all executed cells. To reset the notebook, click 'Restart Kernel' (the circular arrow) -- this will not undo any changes made.

Ex. 2.20 Database connect and cursor(). In a Python program, connect to ../session_2.db (returning a connection object) and call .cursor() on it to get a cursor object we will use for querying. (Note the ../ assumes that we are in a directory above the session_2.db file.)

Close the database connection with conn.close() when finished.

import sqlite3

db_filename = '../session_2.db'
 
Ex. 2.21 Result set: for looping. Use the cursor object to .execute() a SELECT query for all columns in the revenue table, and loop through the result set object with a for loop, printing each row. Close the database connection when done.
import sqlite3

db_filename = '../session_2.db'

conn = sqlite3.connect(db_filename)

c = conn.cursor()
 
Ex. 2.22 Result set: .fetchone(). Use the cursor object to .execute() a SELECT query for all columns in the revenue table WHERE company = 'Westfield', and use .fetchone() to retrieve the single result row (tuple) of values. Close the database connection when done.
import sqlite3

db_filename = '../session_2.db'

conn = sqlite3.connect(db_filename)

c = conn.cursor()

c.execute("SELECT * FROM revenue WHERE company = 'Westfield'")
 
Ex. 2.23 Result set: .fetchmany(). Use the cursor object to .execute() a SELECT query for all columns in the revenue table. Use .fetchmany(3) to retrieve just 3 rows, then use .fetchmany(4) again to retrieve the remaining 4 rows. Close the database connection when done.
import sqlite3

db_filename = '../session_2.db'

conn = sqlite3.connect(db_filename)

c = conn.cursor()

c.execute('SELECT * FROM revenue')
 
Ex. 2.24 Result set: .fetchall(). Use the cursor object to .execute() a SELECT query for all columns in the revenue table. Use .fetchall() to retrieve all rows in the result set as a list of tuples. Close the database connection when done.
import sqlite3

db_filename = '../session_2.db'

conn = sqlite3.connect(db_filename)

c = conn.cursor()

c.execute("SELECT * FROM revenue")
 
Ex. 2.25 Show table columns. After doing a select * query, use the cursor .description attribute to see the names of columns in a table, which are nested in a list of tuples. Then pull out just the first item in each tuple to get a list of columns. Close the database connection when done.
import sqlite3

db_filename = '../session_2.db'

conn = sqlite3.connect(db_filename)

c = conn.cursor()

c.execute('SELECT * FROM revenue LIMIT 1')

We're using a LIMIT 1 to pull just one row from the table, which will have all columns.

 
Ex. 2.26 INSERT query. Use the cursor object to .execute() an INSERT query, inserting a name, state and cost value into the revenue table. Use parameterized arguments (?) to perform the insertions without having to worry about enquoting or escaping values in the query.

Make sure to call conn.commit() (where conn is the connection object) to see results. Also remember to close the database connection when done. After running, return to your SQLite3 session and perform a SELECT * query so you can see the new row.

import sqlite3

db_filename = '../session_2.db'

conn = sqlite3.connect(db_filename)

c = conn.cursor()

query = 'INSERT INTO revenue VALUES (?, ?, ?)'

If you don't see the change, make sure you executed conn.commit() after executing the insert.

 

CSV: review

Ex. 2.27 Write a row to a csv. Open a new file new.csv for writing (remember that this will truncate (blank out) the file). Using write.writerow(), write the header row first, then the data in row and row2 to the file. Make sure to close the file before finishing (especially in Jupyter, where the program does not stop running and so the file will not be closed until you close the notebook). To confirm, open the file directly in a text editor or Excel to view it.
import csv

header = ['name', 'state', 'country']
row = ['Joe', 'CA', 'USA']
row2 = ['Mary', 'NY', 'USA']

wfh = open('../new.csv', 'w', newline='')
writer = csv.writer(wfh)
 
Ex. 2.28 Write several rows to csv. Open the file new2.csv for writing and use writer.writerow() to write the header, followed by using writer.writerows() to write the entire list of tuples, to the file. Make sure to close the file after writing.
import csv

header = ['name', 'state', 'country']
rows = [ ('Joe', 'CA', 'USA'),
         ('Mary' ,'NY', 'USA') ]

wfh = open('../new2.csv', 'w', newline='')
writer = csv.writer(wfh)
 

LAB 2

Ex. 2.29 Connect to a database and generate a cursor object.

Remember that from exercise files, any data file will be located in the parent directory. So the correct location for this week's database file is session_2.db.

Confirm that you have connected to the existing database with this query:
SELECT name FROM sqlite_master WHERE type= "table"
Expected Output:
('ad_companies',)
('ad_buys',)
('students',)
('revenue',)
('student_status',)
('user',)
('user_classes',)
('companyrev',)
('planets',)
 
Ex. 2.30 SELECT query from planets table.

Select all columns and rows from the 'planets' table (created in the previous lab), then use 'for' to loop over and print each row of results.

import sqlite3

conn = sqlite3.connect('../session_2.db')
cursor = conn.cursor()
Expected Output:
('Mercury', '0.33', '58')
('Venus', '4.87', '108')
('Earth', '5.98', '150')
 
Ex. 2.31 Use .fetchone() to retrieve one row.

Select all columns from the user table where user_id is equal to 2. Use .fetchone() to retreieve the row.

import sqlite3

conn = sqlite3.connect('../session_2.db')
cursor = conn.cursor()
Expected Output:
(2, 'joe', 'pass', 'Joe', 'Wilson')
 
Ex. 2.32 Use .fetchall() to retrieve all rows.

Select all columns from the students table where state is equal to NJ. Use .fetchall() to retreieve the rows.

import sqlite3

conn = sqlite3.connect('../session_2.db')
cursor = conn.cursor()
Expected Output:
('jb23', '115 Karas Dr.', 'Jersey City', 'NJ', '07127')
('jb29', '119 Xylon Dr.', 'Jersey Cit', 'NJ', '07127')
 
Ex. 2.33 Read a table description.

After doing a select * query on the students table, use the cursor .description attribute to retrive a tuple of tuples with tables names:

( ('id', None, None, None, None, None, None),
  ('address', None, None, None, None, None, None),
  ('city', None, None, None, None, None, None),
  ('state', None, None, None, None, None, None),
  ('zip', None, None, None, None, None, None)     )
import sqlite3

conn = sqlite3.connect('../session_2.db')
cursor = conn.cursor()

query = 'SELECT * FROM students LIMIT 1'

Next, use a list comprehension to retrieve a list of names:

Expected Output:
['id', 'address', 'city', 'state', 'zip']
 
Ex. 2.34 Insert a row.

Insert a new row into the planets table with the following data:

Mars    64.20    228
import sqlite3

conn = sqlite3.connect('../session_2.db')
cursor = conn.cursor()

After committing the insert with conn.commit(), issue a SELECT query to confirm that the row has been inserted.

 
Ex. 2.35 Loop through database results and write rows to CSV.

Select all rows from the planets table and insert them into a new file ../planets.csv file that you open for writing and write row-by row using a csv.writer object. (Make sure to include the newline='' argument when opening the file, and to close the write file at the end.)

import sqlite3

conn = sqlite3.connect('../session_2.db')
cursor = conn.cursor()
The resulting file should look like this:
Mercury,0.33,58
Venus,4.87,108
Earth,5.98,150
Mars,64.2,228
 

JSON / MULTIDIMENSIONAL STRUCTURES

Ex. 2.36 View and loop through list of dicts. Open weather_newyork_lod.json in a text editor or PyCharm. This is a list of dicts -- a list where each item in the list is a dict.

Now open this file in Python and load the JSON into a Python object with json.load(). Loop through the list of dicts and print each dict.

import json

fh = open('../weather_newyork_lod.json')
lod = json.load(fh)
 
Ex. 2.37 Print value from list of dicts. Again open the file weather_newyork_lod.json in Python and load the JSON into a Python object with json.load().

Loop through each dict in the list of dicts and print just the 'date' column.

import json

fh = open('../weather_newyork_lod.json')
lod = json.load(fh)
 
Ex. 2.38 View and loop through a dict of dicts. Open weather_newyork_dod.json in a text editor or PyCharm. This is a dict of dicts -- a dict where each key in the dict is a string, and each value in the dict is a dict.

Now open this file in Python and load the JSON into a Python object with json.load(). Loop through the dict of dicts and print each key and associated value in the dict.

import json

fh = open('../weather_newyork_dod.json')
dod = json.load(fh)
 
Ex. 2.39 Loop through a dict of dicts and print a value from each. Again open the file weather_newyork_dod.json in Python and load the JSON into a Python object with json.load().

Loop through each key and value in the dict of dicts and from each dict value print the 'mean_temp' value.

import json

fh = open('../weather_newyork_dod.json')
dod = json.load(fh)
 
Ex. 2.40 Travel to an inner structure. Open the file ip_routes.json in a text editor and examine the structure. Scroll down until you see a repeating dict of dicts nested within the structure.

Now open the file in your Python code and load it into an object with json.load(). See if you can reach the repeating dict of dicts using a single statement of chained dict and/or list subscripts. Print this 'inner' structure (dict of dicts) using json.dumps() with the indent=4 parameter argument.

import json

fh = open('../ip_routes.json')
struct = json.load(fh)
 
Ex. 2.41 Build a dict from a CSV file with CSV header keys. Use csv to open revenue.csv in a Python file and select out: the header row and the first data row (hint: use next() on the reader object to get one line at a time from the file).

Now build a dict from the header row and first data row with keys that match the header line. Tip: use dict(zip(headers, data_row)) to build the dict: zip() takes two lists and "zips" them together like a zipper to pair up the first items in each list, the second items in each list, etc. zip(headers, data_row) will pair up the column heads with data from the row, and passing this to dict() will transform to a dictionary.

import csv

fh = open('../revenue.csv')
reader = csv.reader(fh)
 
Ex. 2.42 Build a list of dicts. Incorporating what you did in the previous assignment, now loop through the file and build a dict of header keys and row values for each data row in the revenue.csv file. Print each of the dicts as you build them.

Now initialize a new empty list before the loop begins. As you build each dict, append the dict to the list. Print the resulting structure once completed. Finally, use print(json.dumps(lod, indent=4)) to print the structure in a friendly format.

import csv
import json

fh = open('../revenue.csv')
reader = csv.reader(fh)

lod = []

header = next(reader)
 
Ex. 2.43 Build a dict of dicts. Adapting what you did in the prior solution, now loop through the file and build a dict of header keys and row values for each data row in the revenue.csv file. Print each of the dicts as you build them.

Now initialize a new empty dict before the loop begins. As you build each dict, add the "inner" dict to the "outer" dict: make the company name the key in the "outer" dict, and the value the "inner" dict. Print the resulting structure once completed. Finally, use print(json.dumps(dod, indent=4)) to print the structure in a friendly ("pretty") format.

import csv
import json

fh = open('../revenue.csv')
reader = csv.reader(fh)

dod = {}

header = next(reader)
 

LAB 3

Ex. 2.44 Access item in a list of lists.
lol = [
    [ 1816,   6.7,  'Indiana' ],
    [ 1788,  10.6,  'Georgia' ],
    [ 1819,   4.9,  'Alabama' ]
]

Access the value 10.6 and print it.

Expected Output:
10.6
 
Ex. 2.45 Loop through and print 'column' values in a list of lists.

Using a loop, print the state names one after the other.

lol = [
    [ 1816,   6.7,  'Indiana' ],
    [ 1788,  10.6,  'Georgia' ],
    [ 1819,  4.9,   'Alabama' ]
]
Expected Output:
Indiana
Georgia
Alabama
 
Ex. 2.46 Loop through and print 'column' values in a list of dicts.

Using a loop, print the years one after the other.

lol = [
    { 'name': 'Indiana',
      'year': '1816',
      'pop':  6.7
    },
    { 'name': 'Georgia',
      'year': '1788',
      'pop':  10.6
    },
    { 'name': 'Alabama',
      'year': '1819',
      'pop':  4.9
    }
]
Expected Output:
1816
1788
1819
 
Ex. 2.47 Access item in a dict of dicts.

In a single statement, print 1819.

dod = {
    'Indiana':  {
                   'year': '1816',
                   'pop':  6.7
                },
    'Georgia':  {
                   'year': '1788',
                   'pop':  10.6
                },
    'Alabama':  {
                   'year': '1819',
                   'pop':  4.9
                }
}
Expected Output:
1819
 
Ex. 2.48 Loop through and print 'column' values in a dict of dicts.

Using a loop, print the populations, one after the other.

dod = {
    'Indiana':  {
                   'year': '1816',
                   'pop':  6.7
                },
    'Georgia':  {
                   'year': '1788',
                   'pop':  10.6
                },
    'Alabama':  {
                   'year': '1819',
                   'pop':  4.9
                }
}
Expected Output:
6.7
10.6
4.9
 
Ex. 2.49 Access an item in a complex structure.

Print the value 9.7 in the below structure:

struct = { 'version':  1.1,
           'data': {
                'states': {
                    'Indiana':  {
                                   'year': '1816',
                                   'pop':  [ 6.7, 6.5, 6.1 ]
                                },
                    'Georgia':  {
                                   'year': '1788',
                                   'pop':  [ 10.6, 9.7, 8.2 ]
                                },
                    'Alabama':  {
                                   'year': '1819',
                                   'pop':  [ 4.9, 4.8, 4.4 ]
                                }
                },
                'pop_years':  [ '2019', '2010', '2000']
            }
        }
Expected Output:
9.7
 
Ex. 2.50 Loop through and print 'column' values in a complex structure.

Using a loop, print the values 1816, 1788 and 1819 from the below structure:

struct = { 'version':  1.1,
           'data': {
                'states': {
                    'Indiana':  {
                                   'year': '1816',
                                   'pop':  [ 6.7, 6.5, 6.1 ]
                                },
                    'Georgia':  {
                                   'year': '1788',
                                   'pop':  [ 10.6, 9.7, 8.2 ]
                                },
                    'Alabama':  {
                                   'year': '1819',
                                   'pop':  [ 4.9, 4.8, 4.4 ]
                                }
                },
                'pop_years':  [ '2019', '2010', '2000']
            }
        }
Expected Output:
1816
1788
1819
 
Ex. 2.51 Perform a loop within a loop within a complex structure.

Using a loop nested within another 'for' loop, print each state, print and all 3 population values. For clarity, try indenting each population value, and printing an extra blank line after each state.

struct = { 'version':  1.1,
           'data': {
                'states': {
                    'Indiana':  {
                                   'year': '1816',
                                   'pop':  [ 6.7, 6.5, 6.1 ]
                                },
                    'Georgia':  {
                                   'year': '1788',
                                   'pop':  [ 10.6, 9.7, 8.2 ]
                                },
                    'Alabama':  {
                                   'year': '1819',
                                   'pop':  [ 4.9, 4.8, 4.4 ]
                                }
                },
                'pop_years':  [ '2019', '2010', '2000']
            }
        }
Expected Output:
Indiana
  6.7
  6.5
  6.1

Georgia
  10.6
  9.7
  8.2

Alabama
  4.9
  4.8
  4.4
 
[pr]