Commit 00835736 authored by Trevor Bekolay's avatar Trevor Bekolay
Browse files

Minor updates for Python 3 compatibility

Mostly these are just noticing when Python 3 gives different outputs
than Python 2 and updating accordingly, and a few spots where print
statements were missed (I think these print statements were added
after the PR was made).

One odd thing is that in Python 3, the list returned by `glob` isn't
sorted. I'm not sure if this is also true in Python 2, but to be sure
that the output is correct, I added `sorted` calls.

Another somewhat large change is that the exception classes are changed
in Python 3; importantly, there's no longer a base IOError. Instead,
the specific IOErrors are separated out.
Updated that lesson accordingly.

Things I noticed but didn't change:

1. I found many floats that truncated differently in the lessons
   (e.g., 126.5) that truncated differently in my Python 3 environment
   (e.g., 126.50000000000001). This might be something specific to my
   machine though, not necessarily Python 3?
2. In 02-loop, the challenge "From 1 to N" mentions that range(3)
   produces [0, 1, 2]. In Python 3 it instead produces an object,
   which prints as range(0, 3). You can still iterate over it though,
   so it doesn't directly affect the challenge, but the pedant in me
   has a "well, actually" moment when I read the challenge.
3. In Lesson 6, the difference in standard deviations before and after
   is exactly zero on my machine. I'm not sure if this is, again,
   a machine difference, or if it's a Python 3 difference.
parent a3d62854
......@@ -189,7 +189,7 @@ let's ask what [type](reference.html#type) of thing `data` refers to:
print(type(data))
~~~
~~~ {.output}
<type 'numpy.ndarray'>
<class 'numpy.ndarray'>
~~~
The output tells us that `data` currently refers to an N-dimensional array created by the NumPy library. These data corresponds to arthritis patient's inflammation. The rows are the individual patients and the columns are there daily inflammation measurements.
......
......@@ -142,12 +142,12 @@ If we make a list and (attempt to) copy it then modify in place, we can cause al
odds = [1, 3, 5, 7]
primes = odds
primes += [2]
print 'primes:', primes
print 'odds:', odds
print('primes:', primes)
print('odds:', odds)
~~~
~~~ {.output}
primes [1, 3, 5, 7, 2]
odds [1, 3, 5, 7, 2]
primes: [1, 3, 5, 7, 2]
odds: [1, 3, 5, 7, 2]
~~~
This is because python stores a list in memory, and then can use multiple names to refer to the same list.
......@@ -157,12 +157,12 @@ If all we want to do is copy a (simple) list, we can use the list() command, so
odds = [1, 3, 5, 7]
primes = list(odds)
primes += [2]
print 'primes:', primes
print 'odds:', odds
print('primes:', primes)
print('odds:', odds)
~~~
~~~ {.output}
primes [1, 3, 5, 7, 2]
odds [1, 3, 5, 7]
primes: [1, 3, 5, 7, 2]
odds: [1, 3, 5, 7]
~~~
This is different from how variables worked in lesson 1, and more similar to how a spreadsheet works.
......
......@@ -21,10 +21,11 @@ that finds files whose names match a pattern.
We provide those patterns as strings:
the character `*` matches zero or more characters,
while `?` matches any one character.
We can use this to get the names of all the html files:
We can use this to get the names of all the html files.
We use the `sorted` function to ensure this list is in alphabetical order:
~~~ {.python}
print(glob.glob('*.html'))
print(sorted(glob.glob('*.html')))
~~~
~~~ {.output}
......@@ -43,7 +44,7 @@ Let's test it by analyzing the first three files in the list:
import numpy
import matplotlib.pyplot
filenames = glob.glob('*.csv')
filenames = sorted(glob.glob('*.csv'))
filenames = filenames[0:3]
for f in filenames:
print(f)
......
......@@ -65,47 +65,47 @@ and we have access to the value that we returned.
> ## Integer division {.callout}
>
> We are using Python3 and integer division always return floating point.
> We are using Python 3 and integer division always return floating point.
>
> ~~~ {.python}
> $ python -c "print(5/9)"
> $ python3 -c "print(5/9)"
> ~~~
> ~~~ {.output}
> 0.5555555555555556
> ~~~
>
> **Unfortunately**, in Python2 this isn't the case.
> **Unfortunately**, in Python 2 this isn't the case.
>
> ~~~ {.bash}
> $ python -c "print(5/9)"
> $ python2 -c "print(5/9)"
> ~~~
> ~~~ {.output}
> 0
> ~~~
>
> If you are using Python2 and want a floating point as return of division
> you need to use one of the following forms
> If you are using Python 2 and want a floating point as return of division
> you need to use one of the following forms:
>
> ~~~ {.bash}
> $ python -c "print(float(5)/9)"
> $ python2 -c "print(float(5)/9)"
> ~~~
> ~~~ {.output}
> 0.555555555556
> ~~~
> ~~~ {.bash}
> $ python -c "print(5/float(9))"
> $ python2 -c "print(5/float(9))"
> ~~~
> ~~~ {.output}
> 0.555555555556
> ~~~
> ~~~ {.bash}
> $ python -c "print(5.0/9)"
> $ python2 -c "print(5.0/9)"
> ~~~
> ~~~ {.output}
> 0.555555555556
> ~~~
> ~~~ {.bash}
> $ python -c "print(5/9.0)"
> $ python2 -c "print(5/9.0)"
> ~~~
> ~~~ {.output}
> 0.555555555556
......@@ -268,7 +268,7 @@ print('min, mean, and and max of centered data are:', centered.min(), centered.m
~~~
~~~ {.output}
original min, mean, and max are: 0.0 6.14875 20.0
min, mean, and and max of centered data are: -6.14875 -3.49054118942e-15 13.85125
min, mean, and and max of centered data are: -6.14875 2.84217094304e-16 13.85125
~~~
That seems almost right:
......@@ -491,7 +491,7 @@ help(numpy.loadtxt)
~~~ {.output}
Help on function loadtxt in module numpy.lib.npyio:
loadtxt(fname, dtype=<type 'float'>, comments='#', delimiter=None, converters=None, skiprows=0, usecols=None, unpack=False, ndmin=0)
loadtxt(fname, dtype=<class 'float'>, comments='#', delimiter=None, converters=None, skiprows=0, usecols=None, unpack=False, ndmin=0)
Load data from a text file.
Each row in the text file must have the same number of values.
......
......@@ -14,7 +14,7 @@ minutes: 30
> * `SyntaxError` and `IndentationError`
> * `NameError`
> * `IndexError`
> * `IOError`
> * `FileNotFoundError`
Every programmer encounters errors,
both those who are just beginning,
......@@ -311,25 +311,20 @@ Python is telling us that there is an `IndexError` in our code, meaning we tried
## File Errors
The last type of error we'll cover today are those associated with reading and writing files: `IOError`.
The "IO" in `IOError` stands for "input/output",
which is just a fancy way of saying "reading/writing".
The last type of error we'll cover today are those associated with reading and writing files: `FileNotFoundError`.
If you try to read a file that does not exist,
you will recieve an `IOError` telling you so.
This is the most common reason why you would receive `IOError`,
and if the error messages says "no such file or directory",
then you know you have just tried to access a file that does not exist:
you will recieve an `FileNotFoundError` telling you so.
~~~ {.python}
file_handle = open('myfile.txt', 'r')
~~~
~~~ {.error}
---------------------------------------------------------------------------
IOError Traceback (most recent call last)
FileNotFoundError Traceback (most recent call last)
<ipython-input-14-f6e1ac4aee96> in <module>()
----> 1 file_handle = open('myfile.txt', 'r')
IOError: [Errno 2] No such file or directory: 'myfile.txt'
FileNotFoundError: [Errno 2] No such file or directory: 'myfile.txt'
~~~
One reason for receiving this error is that you specified an incorrect path to the file.
......@@ -347,7 +342,8 @@ However,
if you meant to open a file for reading,
but accidentally opened it for writing,
and then try to read from it,
you will get an error telling you that the file was not opened for reading:
you will get an `UnsupportedOperation` error
telling you that the file was not opened for reading:
~~~ {.python}
file_handle = open('myfile.txt', 'w')
......@@ -355,14 +351,20 @@ file_handle.read()
~~~
~~~ {.error}
---------------------------------------------------------------------------
IOError Traceback (most recent call last)
UnsupportedOperation Traceback (most recent call last)
<ipython-input-15-b846479bc61f> in <module>()
1 file_handle = open('myfile.txt', 'w')
----> 2 file_handle.read()
IOError: File not open for reading
UnsupportedOperation: not readable
~~~
These are the most common errors with files,
though many others exist.
If you get an error that you've never seen before,
searching the Internet for that error type
often reveals common reasons why you might get that error.
> ## Reading Error Messages {.challenge}
>
> Read the traceback below, and identify the following pieces of information about it:
......
......@@ -82,8 +82,8 @@ $ python sys-version.py
~~~
~~~ {.output}
version is 2.7.5 |Anaconda 1.8.0 (x86_64)| (default, Oct 24 2013, 07:02:20)
[GCC 4.0.1 (Apple Inc. build 5493)]
version is 3.4.3+ (default, Jul 28 2015, 13:17:50)
[GCC 4.9.3]
~~~
Create another file called `argv-list.py` and save the following text to it.
......
......@@ -107,11 +107,14 @@ Solutions to exercises:
> ## Computing powers with loops {.challenge}
> Write a loop that calculates the same result as `5 ** 3` using
> multiplication (and without exponentiation).
> ~~~ {.output}
>
> ~~~ {.python}
> result = 1
> for i in range(0,3):
> result = result*5
> print result
> for i in range(0, 3):
> result = result * 5
> print(result)
> ~~~
> ~~~ {.output}
> 125
> ~~~
......@@ -124,8 +127,10 @@ Solutions to exercises:
> oldstring = 'Newton'
> length_old = len(oldstring)
> for char_index in range(length_old):
> newstring = newstring + oldstring[length_old-char_index-1]
> print newstring
> newstring = newstring + oldstring[length_old - char_index - 1]
> print(newstring)
> ~~~
> ~~~ {.output}
> 'notweN'
> ~~~
......@@ -142,7 +147,9 @@ Solutions to exercises:
> my_list = []
> for char in "hello":
> my_list.append(char)
> print my_list
> print(my_list)
> ~~~
> ~~~ {.output}
> ["h", "e", "l", "l", "o"]
> ~~~
......@@ -158,30 +165,35 @@ Solutions to exercises:
>
> ~~~ {.python}
> if 4 > 5:
> print 'A'
> print('A')
> elif 4 == 5:
> print 'B'
> print('B')
> elif 4 < 5:
> print 'C'
> ~~~
> ~~~ {.output}
> C gets printed, because the first two conditions, `4<5` and `4==5` are not true, but `4<5` is true.
> print('C')
> ~~~
>
> C gets printed, because the first two conditions, `4 > 5` and `4 == 5` are not true, but `4 < 5` is true.
>
> ## What is truth? {.challenge}
>
> After reading and running the code below,
> explain the rules for which values are considered true and which are considered false.
> (Note that if the body of a conditional is a single statement, we can write it on the same line as the `if`.)
>
> ~~~ {.python}
> if '': print 'empty string is true'
> if 'word': print 'word is true'
> if []: print 'empty list is true'
> if [1, 2, 3]: print 'non-empty list is true'
> if 0: print 'zero is true'
> if 1: print 'one is true'
> if '':
> print('empty string is true')
> if 'word':
> print('word is true')
> if []:
> print('empty list is true')
> if [1, 2, 3]:
> print('non-empty list is true')
> if 0:
> print('zero is true')
> if 1:
> print('one is true')
> ~~~
> ~~~ {.output}
> First line prints nothing: an empty string is false
......@@ -200,14 +212,15 @@ Solutions to exercises:
> a = 5
> b = 5.1
>
> if abs(a-b) < 0.1*abs(b):
> print 'True'
> if abs(a - b) < 0.1 * abs(b):
> print('True')
> else:
> print 'False'
> print('False')
> ~~~
> Another possible solution:
> ~~~ {.output}
> print abs(a-b) < 0.1*abs(b)
>
> ~~~ {.python}
> print(abs(a - b) < 0.1 * abs(b))
> ~~~
> This works because the Boolean objects `True` and `False` have string representations which can be `print`ed.
......@@ -227,7 +240,9 @@ Solutions to exercises:
> pass
> else:
> negative_sum += num
> print positive_sum, negative_sum
> print(positive_sum, negative_sum)
> ~~~
> ~~~ {.output}
> 21 -14
> ~~~
> Here `pass` means "don't do anything". In this particular case, it's not actually needed, since if `num==0` neither
......@@ -289,11 +304,11 @@ Solutions to exercises:
> (Hint: If $L$ and $H$ are the lowest and highest values in the original array,
> then the replacement for a value $v$ should be $(v-L) / (H-L)$.)
>
> ~~~ {.output}
> ~~~ {.python}
> def rescale(input_array):
> L = input_array.min()
> H = input_array.max()
> output_array = (input_array - L)/float(H-L)
> output_array = (input_array - L) / (H - L)
> return output_array
> ~~~
......@@ -328,8 +343,8 @@ Solutions to exercises:
> '''rescales input array values to lie between low_val and high_val'''
> L = input_array.min()
> H = input_array.max()
> intermed_array = (input_array - L)/float(H-L)
> output_array = intermed_array*(high_val-low_val) + low_val
> intermed_array = (input_array - L) / (H - L)
> output_array = intermed_array * (high_val - low_val) + low_val
> return output_array
> ~~~
......@@ -345,11 +360,11 @@ Solutions to exercises:
> k = ((f-32)*(5.0/9.0)) + 273.15
> return k
>
> print f2k(8)
> print f2k(41)
> print f2k(32)
> print(f2k(8))
> print(f2k(41))
> print(f2k(32))
>
> print k
> print(k)
> ~~~
>
> ~~~ {.output}
......@@ -393,7 +408,7 @@ Solutions to exercises:
> /Users/jhamrick/project/swc/novice/python/errors_02.py in print_message(day)
> 9 "sunday": "Aw, the weekend is almost over."
> 10 }
> ---> 11 print messages[day]
> ---> 11 print(messages[day])
> 12
> 13
>
......@@ -419,16 +434,16 @@ Solutions to exercises:
>
> ~~~ {.python}
> def another_function
> print "Syntax errors are annoying."
> print "But at least python tells us about them!"
> print "So they are usually not too hard to fix."
> print("Syntax errors are annoying.")
> print("But at least python tells us about them!")
> print("So they are usually not too hard to fix.")
> ~~~
> ~~~ {.output}
> `SyntaxError` for missing `:()` at end of first line, `IndentationError` for mismatch between second and third lines.
> def another_function():
> print "Syntax errors are annoying."
> print "But at least python tells us about them!"
> print "So they are usually not too hard to fix."
> print("Syntax errors are annoying.")
> print("But at least python tells us about them!")
> print("So they are usually not too hard to fix.")
> ~~~
> ## Identifying Variable Name Errors {.challenge}
......@@ -445,7 +460,7 @@ Solutions to exercises:
> message = message + a
> else:
> message = message + "b"
> print message
> print(message)
> ~~~
> ~~~ {.output}
> 3 `NameError`s for `number` being misspelled, for `message` not defined, and for `a` not being in quotes.
......@@ -456,7 +471,9 @@ Solutions to exercises:
> message = message + "a"
> else:
> message = message + "b"
> print message
> print(message)
> ~~~
> ~~~ {.output}
> abbabbabba
> ~~~
......@@ -468,12 +485,12 @@ Solutions to exercises:
>
> ~~~ {.python}
> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
> print 'My favorite season is ', seasons[4]
> print('My favorite season is ', seasons[4])
> ~~~
> ~~~ {.output}
> IndexError; the last entry is `seasons[3]`, so `seasons[4]` doesn't make sense.
> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
> print 'My favorite season is ', seasons[-1]
> print('My favorite season is ', seasons[-1])
> ~~~
## [Defensive Programming](08-defensive.html)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment