Chapter 1
Python Primer
The first chapter in the book is all about learning to handle Python syntax. Subjects include objects, control flow, functions, I/O operations, exceptions, iterators and generators, namespaces, modules, and scope. There is nothing regarding python packaging to redistribute your own module, which is a subject of its own.
1.1 Format
All exercises will be presented with their own Python Doctest documentation to allow testing. To run them in your own python package you can copy paste the text and add a main like the following:
This is just to try to keep it as simple as possible while adding how to run the code in your own work environment.
Pro-Tip. JetBrains Pycharm is awesome, I really recommend it, plus they got a Community Edition if you are pennyless like me. The colors, the functionality it just rocks. Plus the IDE can run the examples without the need of using a main function.
Pro-Tip. I like to use Anaconda for my Python distro, but the standalone Python or works too.
1.1.1 Exercises
The exercises in the first chapter are fun, no joke. I’ve seen what’s coming in chapter 2 and those exercises look terrible because they are open ended questions, but they are also important concepts.
R-1.1
| Go to Top |
|
Write a short Python function, is_multiple(n, m)
, that takes two integer values and returns True
if
is a multiple
of , that is,
for some
integer ,
and False
otherwise.
: Exercise R-1.1
”””Write a short Python function, is_multiple(n, m), that takes two integer
values and returns True if n is a multiple of m, that is, n = mi for some
integer i, and False otherwise.
>>> is_multiple(50,3)
False
”””
def is_multiple(n, m):
”””Return True if n is multiple of m such that n = mi
Else returns False
>>> is_multiple(50,3)
False
>>> is_multiple(60,3)
True
>>> is_multiple(70,3)
False
>>> is_multiple(−50,2)
True
>>> is_multiple(−60,2)
True
>>> is_multiple(”test”,10)
Numbers must be Integer values
>>> is_multiple(−60,”test”)
Numbers must be Integer values
”””
try:
return True if (int(n) % int(m) == 0) else False
except ValueError:
print(”Numbers must be Integer values”)
R-1.2
| Go to Top |
|
Write a short Python function, is_even(k)
, that takes an integer value and returns True
if
is
even, and False
otherwise. However, your function cannot use the multiplication, modulo, or division
operators.
: Exercise R-1.2
”””Write a short Python function, is_even(k), that takes an integer value and
returns True if k is even, and False otherwise. However, your function
cannot use the multiplication, modulo, or division operators
>>> is_even(127)
False
”””
def is_even(k):
”””Return True if n is even
Else returns False
>>> is_even(10)
True
>>> is_even(9)
False
>>> is_even(11)
False
>>> is_even(13)
False
>>> is_even(1025)
False
>>> is_even(”test”)
Number must be Integer values
”””
try:
return int(k) & 1 == 0
except ValueError:
print(”Number must be Integer values”)
R-1.3
| Go to Top |
|
Write a short Python function, minmax(data)
, that takes a sequence of one or more numbers, and returns the
smallest and largest numbers, in the form of a tuple of length two. Do not use the built-in functions min
or max
in
implementing your solution.
: Exercise R-1.3
””” Write a short Python function, minmax(data), that takes a sequence of
one or more numbers, and returns the smallest and largest numbers, in the
form of a tuple of length two. Do not use the built−in functions min or
max in implementing your solution.
>>> print(minmax([2,3,4,5,6,7,8,9,10,11,10,9,8,7,6,5,4,3,2,1]))
Min 1 − Max 11
”””
class MinMax():
”””MinMax object helper
Attributes:
min (int): Minimun value of attributes
max (max): Maximum value of attributes
”””
def __init__(self, min, max):
””” Default Constructor
Args:
min (int): Number with lesser value
max (int): Number with higher value
”””
self.min = min
self.max = max
def __str__(self):
”””String representation overload
”””
return ”Min {min} − ” ∖
”Max {max}”.format(min=str(self.min),
max=str(self.max))
def minmax(data):
”””This is the algorithm to find the
minimum and maximun in a list.
Args:
data (list of int): Simple array of
Integers
Returns:
A tuple MinMax that holds the minimum
and maximum values found in the list
Examples:
Here are some examples!
>>> print(minmax([2,3,4,5,6,7,8,9,10,11,10,9,8,7,6,5,4,3,2,1]))
Min 1 − Max 11
>>> print(minmax([50,200,300,3,78,19203,56]))
Min 3 − Max 19203
>>> print(minmax([100,150,200,500]))
Min 100 − Max 500
”””
start = 0
mm = MinMax(data[start],data[start])
if len(data) & 1 == 1:
if data[start] < data[start+1]:
mm.max = data[start+1]
mm.min = data[start]
start += 2
else:
start += 1
for index in range(start, len(data[start:]), 2):
if data[index] < data[index+1] :
l_min = data[index]
l_max = data[index+1]
else:
l_min = data[index+1]
l_max = data[index]
if mm.min > l_min:
mm.min = l_min
if mm.max < l_max:
mm.max = l_max
return mm
R-1.4 & R-1.5
| Go to Top |
|
Write a short Python function that takes a positive integer and returns the sum of the squares of all the positive integers smaller than .
Give a single command that computes the sum from Exercise R-1.4, relying on Python’s comprehension syntax and the built-in sum function.
: Exercise R-1.4 & R-1.5
””” Write a short Python function that takes a positive integer n and returns
the sum of the squares of all the positive integers smaller than n.
Give a single command that computes the sum from Exercise R−1.4, relying
on Pythons comprehension syntax and the built−in sum function.
>>> sum_of_squares(10)
285
”””
def sum_of_squares(n):
”””Sum of squares of postive integers
smaller than n
Args:
n (int): Highest number
>>> sum_of_squares(10)
285
>>> sum_of_squares(20)
2470
>>> sum_of_squares(500)
41541750
>>> sum_of_squares(37)
16206
>>> sum_of_squares(−1)
False
”””
return sum([pow(x,2) for x in range(n)]) if n > 0 else False
R-1.6 & R-1.7
| Go to Top |
|
Write a short Python function that takes a positive integer and returns the sum of the squares of all the odd positive integers smaller than .
Give a single command that computes the sum from Exercise R-1.6, relying on Python’s comprehension syntax and the built-in sum function.
: Exercise R-1.6 & R-1.7
”””Write a short Python function that takes a positive integer n and returns
the sum of the squares of all the odd positive integers smaller than n.
Give a single command that computes the sum from Exercise R−1.6, rely−
ing on Python’s comprehension syntax and the built−in sum function.
”””
def sum_of_odd_squares(n):
”””Sum of squares of odd postive integers
smaller than n
Args:
n (int): Highest number
>>> sum_of_odd_squares(10)
165
>>> sum_of_odd_squares(20)
1330
>>> sum_of_odd_squares(500)
20833250
>>> sum_of_odd_squares(37)
7770
>>> sum_of_odd_squares(−1)
False
”””
return sum([pow(x,2) for x in range(1, n, 2)]) if n > 0 else False
R-1.8
| Go to Top |
|
Python allows negative integers to be used as indices into a sequence, such as a string. If string has length , and expression is used for index , what is the equivalent index such that references the same element?
: Exercise R-1.8
”””Python allows negative integers to be used as indices into a sequence,
such as a string. If string s has length n, and expression s[k] is used for in−
dex −n<=k<0, what is the equivalent index j>=0such that s[j] references
the same element?
>>> l = [2,3,4,5,6,7,8,9,10,11,10,9,8,7,6,5,4,3,2,1]
>>> return_element(l, 0)
(2, −20)
>>> return_element(l, 1)
(3, −19)
>>> return_element(l, 2)
(4, −18)
”””
def return_element(data, k):
”””Tells you the equivalent negative index
Args:
data (list of int): Simple array
k (int): index you want to know
the equivalent negative index
Returns:
(val, index)
val (object): element at position k
index: negative index of that position
Examples:
Here are some examples!
>>> l = [2,3,4,5,6,7,8,9,10,11,10,9,8,7,6,5,4,3,2,1]
>>> return_element(l, 0)
(2, −20)
>>> return_element(l, 1)
(3, −19)
>>> return_element(l, 2)
(4, −18)
”””
idx = k−len(data)
return data[idx], idx if data else False
R-1.9
| Go to Top |
|
What parameters should be sent to the range constructor, to produce a range with values 50, 60, 70, 80?
: Exercise R-1.9
”””What parameters should be sent to the range constructor, to produce a
range with values 50, 60, 70, 80?
>>> range_from_fifty()
[50, 60, 70, 80]
”””
def range_from_fifty():
””” Creates a list
with values 50, 60, 70, 80
Returns:
list: [50, 60, 70, 80]
>>> range_from_fifty()
[50, 60, 70, 80]
”””
return range(50,81,10)
R-1.10
| Go to Top |
|
What parameters should be sent to the range constructor, to produce a range with values 8, 6, 4, 2, 0, -2, -4, -6, -8?
: Exercise R-1.10
””” What parameters should be sent to the range constructor, to produce a
range with values 8, 6, 4, 2, 0, −2, −4, −6, −8?
>>> range_from_eigth()
[8, 6, 4, 2, 0, −2, −4, −6, −8]
”””
def range_from_eigth():
””” Return the list [8, 6, 4, 2, 0, −2, −4, −6, −8]
:return:
the list [8, 6, 4, 2, 0, −2, −4, −6, −8]
>>> range_from_eigth()
[8, 6, 4, 2, 0, −2, −4, −6, −8]
”””
return range(8, −9, −2)
R-1.11
| Go to Top |
|
Demonstrate how to use Python’s list comprehension syntax to produce the list [1, 2, 4, 8, 16, 32, 64, 128, 256].
: Exercise R-1.11
”””Demonstrate how to use Python’s list
comprehension syntax to produce the list
[1, 2, 4, 8, 16, 32, 64, 128, 256].
>>> list_comprehension_example()
[1, 2, 4, 8, 16, 32, 64, 128, 256]
”””
def list_comprehension_example():
””” Return list
[1, 2, 4, 8, 16, 32, 64, 128, 256]
:return:
list: [1, 2, 4, 8, 16, 32, 64, 128, 256]
>>> list_comprehension_example()
[1, 2, 4, 8, 16, 32, 64, 128, 256]
”””
return [pow(2,x) for x in range(9)]
R-1.12
| Go to Top |
|
This is a random method, I usually stress test anything that is random since I am always uneasy about it.
Python’s random module includes a function choice(data) that returns a random element from a non-empty sequence. The random module includes a more basic function randrange, with parametrization similar to the built-in range function, that return a random choice from the given range. Using only the randrange function, implement your own version of the choice function.
: Exercise R-1.12
””” Python’s random module includes a function choice(data) that returns a
random element from a non−empty sequence. The random module includes
a more basic function randrange, with parametrization similar to
the built−in range function, that return a random choice from the given
range. Using only the randrange function, implement your own version
of the choice function.
>>> data = [2,3,4,5,6,7,8,9,10,11,10,9,8,7,6,5,4,3,2,1]
>>> results = list()
>>> for x in range(len(data)∗20):
... val = custom_choice(data)
... results.append(val in data)
>>> print(results)
[True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True, ∖
True, True, True, True, True, True, True, True, True, True]
”””
def custom_choice(data):
import random
return data[random.randrange(0,len(data))]
C-1.13
| Go to Top |
|
Write a pseudo-code description of a function that reverses a list of integers, so that the numbers are listed in the opposite order than they were before, and compare this method to an equivalent Python function for doing the same thing.
: Exercise C-1.13
”””Write a pseudo−code description of a function that reverses a list of n
integers, so that the numbers are listed in the opposite order than they
were before, and compare this method to an equivalent Python function
for doing the same thing.
>>> l1 = [2,3,4,5,6,7,8,9,10,11,10,9,8,7,6,5,4,3,2,1]
>>> custom_reverse(l1)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2]
”””
import cProfile
def custom_reverse(data):
””” Reverse the data array
:param data: a list of elements
:return: reverse list
>>> l1 = [2,3,4,5,6,7,8,9,10,11,10,9,8,7,6,5,4,3,2,1]
>>> custom_reverse(l1)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2]
”””
return [data[len(data)−x−1] for x in range(len(data))]
def standard_reverse(data):
return reversed(data)
def other_reverse(data):
return data[::−1]
if __name__ == ”__main__”:
l1 = [2,3,4,5,6,7,8,9,10,11,10,9,8,7,6,5,4,3,2,1]
l2 = [2,3,4,5,6,7,8,9,10,11,10,9,8,7,6,5,4,3,2,1]
l3 = [2,3,4,5,6,7,8,9,10,11,10,9,8,7,6,5,4,3,2,1]
cProfile.run(’custom_reverse(l1)’)
cProfile.run(’standard_reverse(l2)’)
cProfile.run(’other_reverse(l3)’)
cProfile Results
Here is a simple cProfile with the results. Time shows as but the number of function calls tell us our implementation is not that good.
25 function calls in 0.000 seconds
Ordered by: custom_reverse
ncalls | tottime | percall | cumtime | percall | filename:lineno(function) |
string:1(module) | |||||
c113.py:14(custom_reverse) | |||||
len | |||||
method ’disable’ of ’_lsprof.Profiler’ objects | |||||
range | |||||
3 function calls in 0.000 seconds
Ordered by: standard_reverse
ncalls | tottime | percall | cumtime | percall | filename:lineno(function) |
string:1(module) | |||||
c113.py:26(standard_reverse) | |||||
method ’disable’ of ’_lsprof.Profiler’ objects | |||||
3 function calls in 0.000 seconds
Ordered by: other_reverse
ncalls | tottime | percall | cumtime | percall | filename:lineno(function) |
string:1(module) | |||||
c113.py:29(other_reverse) | |||||
method ’disable’ of ’_lsprof.Profiler’ objects | |||||
C-1.14
| Go to Top |
|
Write a short Python function that takes a sequence of integer values and determines if there is a distinct pair of numbers in the sequence whose product is odd.
In this method what we do first is remove all the repeated elements, then we just extract all the odd numbers. Multiply any of the odd numbers and you get an odd number. Any even number multiplied by an odd number returns an even number.
: Exercise C-1.14
””” Write a short Python function that takes a sequence of integer values and
determines if there is a distinct pair of numbers in the sequence whose
product is odd.
>>> data = [2,3,4,5,6,7,8,9,10,11,10,9,8,7,6,5,4,3,2,1]
>>> get_odd_numbers(data)
[1, 3, 5, 7, 9, 11]
”””
def get_odd_numbers(data):
””” Returns all the numbers whose product is odd
:param data: A list of integers
:return: numbers whose product is odd
”””
s = set(data)
return [k for k in s if (k & 1 == 1)]
C-1.15
| Go to Top |
|
Write a Python function that takes a sequence of numbers and determines if all the numbers are different from each other (that is, they are distinct).
We just build a set from the original list, if the length of the set is smaller, we have repeated numbers. Besides this, we could also sort the elements and look for a repeated element.
: Exercise C-1.15
””” Write a Python function that takes a sequence of numbers and determines
if all the numbers are different from each other (that is, they are distinct).
>>> data = [2,3,4,5,6,7,8,9,10,11,10,9,8,7,6,5,4,3,2,1]
>>> check_if_unique(data)
False
>>> check_if_unique(data[:9])
True
”””
def check_if_unique(data):
””” Check if all elements in list are unique
:param data: list of integers
:return: True if all unique, else False
”””
s = set(data)
return len(s) == len(data)
C-1.16 & C-1.17
| Go to Top |
|
In our implementation of the scale function (page 25), the body of the loop executes the command
data[j] ⋆= factor
. We have discussed that numeric types are immutable, and that use of the
⋆=
operator in this context causes the creation of a new instance (not the mutation of an existing
instance). How is it still possible, then, that our implementation of scale changes the actual
parameter sent by the caller?
Had we implemented the scale function (page 25) as follows, does it work properly?
Explain why or why not.
Well... here are some inmutable types in Python.
- numerical types
- string types
- types
And here are some mutable types.
- lists
- dicts
- classes
So taken by that premise, if we want a function that modifies numeric values in place, we would need a
class
that wraps that numeric value. This is not trivial. So we are going to take respectfully a class done by
The Edwards Research group (http://www.edwards-_research.com/), this class is presented here:
http://blog.edwards-_research.com/2013/09/mutable-_numeric-_types-_in-_python/.
It is everything you dreamed of, I give you, a mutable numeric.
: Mutable Numeric
”””
MutableNum class from: http://blog.edwards−research.com/2013/09/mutable−numeric−types−in−python/
Allows you to pass the instance to a function, and with proper coding, allows you to modify the
value of the instance inside the function and have the modifications persist.
For example, consider:
> def foo(x): x ∗= 2
> x = 5
> foo(x)
> print(x)
This will print 5, not 10 like you may have hoped. Now using the MutableNum class:
> def foo(x): x ∗= 2
> x = MutableNum(5)
> foo(x)
> print(x)
This ∗will∗ print 10, as the modifications you made to x inside of the function foo will persist.
Note, however, that the following ∗will not∗ work:
> def bar(x): x = x ∗ 2
> x = MutableNum(5)
> bar(x)
> print(x)
The difference being that [x ∗= 2] modifies the current variable x, while [x = x ∗ 2] creates a new
variable x and assigns the result of the multiplication to it.
If, for some reason you can’t use the compound operators ( +=, −=, ∗=, etc.), you can do something
like the following:
> def better(x):
> t = x
> t = t ∗ 2
> # ... (Some operations on t) ...
>
> # End your function with a call to x.set()
> x.set(t)
”””
class MutableNum(object):
__val__ = None
def __init__(self, v): self.__val__ = v
# Comparison Methods
def __eq__(self, x): return self.__val__ == x
def __ne__(self, x): return self.__val__ != x
def __lt__(self, x): return self.__val__ < x
def __gt__(self, x): return self.__val__ > x
def __le__(self, x): return self.__val__ <= x
def __ge__(self, x): return self.__val__ >= x
def __cmp__(self, x): return 0 if self.__val__ == x else 1 if self.__val__ > 0 else −1
# Unary Ops
def __pos__(self): return self.__class__(+self.__val__)
def __neg__(self): return self.__class__(−self.__val__)
def __abs__(self): return self.__class__(abs(self.__val__))
# Bitwise Unary Ops
def __invert__(self): return self.__class__(˜self.__val__)
# Arithmetic Binary Ops
def __add__(self, x): return self.__class__(self.__val__ + x)
def __sub__(self, x): return self.__class__(self.__val__ − x)
def __mul__(self, x): return self.__class__(self.__val__ ∗ x)
def __div__(self, x): return self.__class__(self.__val__ / x)
def __mod__(self, x): return self.__class__(self.__val__ % x)
def __pow__(self, x): return self.__class__(self.__val__ ∗∗ x)
def __floordiv__(self, x): return self.__class__(self.__val__ // x)
def __divmod__(self, x): return self.__class__(divmod(self.__val__, x))
def __truediv__(self, x): return self.__class__(self.__val__.__truediv__(x))
# Reflected Arithmetic Binary Ops
def __radd__(self, x): return self.__class__(x + self.__val__)
def __rsub__(self, x): return self.__class__(x − self.__val__)
def __rmul__(self, x): return self.__class__(x ∗ self.__val__)
def __rdiv__(self, x): return self.__class__(x / self.__val__)
def __rmod__(self, x): return self.__class__(x % self.__val__)
def __rpow__(self, x): return self.__class__(x ∗∗ self.__val__)
def __rfloordiv__(self, x): return self.__class__(x // self.__val__)
def __rdivmod__(self, x): return self.__class__(divmod(x, self.__val__))
def __rtruediv__(self, x): return self.__class__(x.__truediv__(self.__val__))
# Bitwise Binary Ops
def __and__(self, x): return self.__class__(self.__val__ & x)
def __or__(self, x): return self.__class__(self.__val__ | x)
def __xor__(self, x): return self.__class__(self.__val__ ˆ x)
def __lshift__(self, x): return self.__class__(self.__val__ << x)
def __rshift__(self, x): return self.__class__(self.__val__ >> x)
# Reflected Bitwise Binary Ops
def __rand__(self, x): return self.__class__(x & self.__val__)
def __ror__(self, x): return self.__class__(x | self.__val__)
def __rxor__(self, x): return self.__class__(x ˆ self.__val__)
def __rlshift__(self, x): return self.__class__(x << self.__val__)
def __rrshift__(self, x): return self.__class__(x >> self.__val__)
# Compound Assignment
def __iadd__(self, x): self.__val__ += x; return self
def __isub__(self, x): self.__val__ −= x; return self
def __imul__(self, x): self.__val__ ∗= x; return self
def __idiv__(self, x): self.__val__ /= x; return self
def __imod__(self, x): self.__val__ %= x; return self
def __ipow__(self, x): self.__val__ ∗∗= x; return self
# Casts
def __nonzero__(self): return self.__val__ != 0
def __int__(self): return self.__val__.__int__() # XXX
def __float__(self): return self.__val__.__float__() # XXX
def __long__(self): return self.__val__.__long__() # XXX
# Conversions
def __oct__(self): return self.__val__.__oct__() # XXX
def __hex__(self): return self.__val__.__hex__() # XXX
def __str__(self): return self.__val__.__str__() # XXX
# Random Ops
def __index__(self): return self.__val__.__index__() # XXX
def __trunc__(self): return self.__val__.__trunc__() # XXX
def __coerce__(self, x): return self.__val__.__coerce__(x)
# Represenation
def __repr__(self): return ”%s(%d)” % (self.__class__.__name__, self.__val__)
# Define innertype, a function that returns the type of the inner value self.__val__
def innertype(self): return type(self.__val__)
# Define set, a function that you can use to set the value of the instance
def set(self, x):
if isinstance(x, (int, long, float)): self.__val__ = x
elif isinstance(x, self.__class__): self.__val__ = x.__val__
else: raise TypeError(”expected a numeric type”)
# Pass anything else along to self.__val__
def __getattr__(self, attr):
print(”getattr: ” + attr)
return getattr(self.__val__, attr)
Now onto the second question... if numeric types are not valid then of course that method is not going to work. You would need to do something radical like returning a new list. As follows:
We can also change the list number by replacing the value in the list, remember that lists are mutable, so we can change that, we just can’t change the number.
: Exercise C-1.16 & C-1.17
””” In our implementation of the scale function (page 25), the body of the loop
executes the command data[j] ∗= factor. We have discussed that numeric
types are immutable, and that use of the ∗= operator in this context causes
the creation of a new instance (not the mutation of an existing instance).
How is it still possible, then, that our implementation of scale changes the
actual parameter sent by the caller?
Had we implemented the scale function (page 25) as follows, does it work
properly?
def scale(data, factor):
for val in data:
val ∗= factor
Explain why or why not.
>>> import MutableNum
>>> l = [2,3,4,5,6]
>>> e = [MutableNum.MutableNum(x) for x in l]
>>> scale(e, 5)
[MutableNum(10), MutableNum(15), MutableNum(20), MutableNum(25), MutableNum(30)]
>>> scale_in_place(e,0.2)
>>> print(e)
[MutableNum(2), MutableNum(3), MutableNum(4), MutableNum(5), MutableNum(6)]
”””
def scale_in_place(data, factor):
”””scales list to factor in place
:param data: the input list of numbers
:param factor: product factor
:return: list with modified values
”””
for j in range(len(data)):
data[j] ∗= factor
def scale(data, factor):
”””scales list to factor
:param data: the input list of numbers
:param factor: product factor
:return: list with modified values
”””
for j in range(len(data)):
data[j] ∗= factor
return data
C-1.18
| Go to Top |
|
Demonstrate how to use Python’s list comprehension syntax to produce the list
: Exercise C-1.18
”””Demonstrate how to use Python’s list comprehension
syntax to produce the list
[0, 2, 6, 12, 20, 30, 42, 56, 72, 90].
>>> demonstration_list_comprehension()
[0, 2, 6, 12, 20, 30, 42, 56, 72, 90]
”””
def demonstration_list_comprehension():
”””Python List comprehension demonstration
:return: [0, 2, 6, 12, 20, 30, 42, 56, 72, 90]
”””
return [idx∗x for idx, x in enumerate(range(1,11))]
C-1.19
| Go to Top |
|
Demonstrate how to use Python’s list comprehension syntax to produce the list [ a , b , c , ..., z ], but without having to type all 26 such characters literally.
: Exercise C-1.19
”””Demonstrate how to use Python’s list comprehension syntax to produce
the list [ a , b , c , ..., z ], but without having to type all 26 such
characters literally.
>>> demonstration_list_comprehension_abc()
[’a’, ’b’, ’c’, ’d’, ’e’, ’f’, ’g’, ’h’, ’i’, ’j’, ’k’, ’l’, ’m’, ’n’, ’o’, ’p’, ’q’, ’r’, ’s’, ’t’, ’u’, ’v’, ’w’, ’x’, ’y’, ’z’]
”””
def demonstration_list_comprehension_abc():
””” Python list comprehension demonstration
:return:
[’a’, ’b’, ’c’, ’d’, ’e’, ’f’, ’g’, ’h’,
’i’, ’j’, ’k’, ’l’, ’m’, ’n’, ’o’, ’p’,
’q’, ’r’, ’s’, ’t’, ’u’, ’v’, ’w’, ’x’,
’y’, ’z’]
”””
return [chr(x) for x in range(ord(’a’), ord(’z’)+1)]
C-1.20
| Go to Top |
|
Python’s random module includes a function shuffle(data)
that accepts a list of elements and
randomly reorders the elements so that each possible order occurs with equal probability. The
random module includes a more basic function randint(a, b)
that returns a uniformly random
integer from a to b (including both endpoints). Using only the randint
function, implement your
own version of the shuffle function.
: Exercise C-1.20
”””Python’s random module includes a function shuffle(data) that accepts a
list of elements and randomly reorders the elements so that each possi−
ble order occurs with equal probability. The random module includes a
more basic function randint(a, b) that returns a uniformly random integer
from a to b (including both endpoints). Using only the randint function,
implement your own version of the shuffle function.
”””
def sub_shuffle(data, indexlist):
import random
index = random.randint(0, len(indexlist)−1)
rElement = data[indexlist[index]]
indexlist.pop(index)
return rElement
def custome_shuffle(data):
indexes_of_data = range(len(data))
return [sub_shuffle(data, indexes_of_data) for e in range(len(data))]
C-1.21
| Go to Top |
|
Write a Python program that repeatedly reads lines from standard input until an EOFError
is
raised, and then outputs those lines in reverse order (a user can indicate end of input by typing
ctrl-D).
: Exercise C-1.21
””” Write a Python program that repeatedly reads lines from standard input
until an EOFError is raised, and then outputs those lines in reverse order
(a user can indicate end of input by typing ctrl−D).
”””
def read_sdin(data):
age = 1
if age > 0:
try:
age = int(input( ”Enter other person’s age:” ))
data.append(age)
if age <= 0:
print( ”Your age must be positive” )
read_sdin(data)
except ValueError:
print( ”That is an invalid age specification” )
read_sdin(data)
except EOFError:
print(data)
print( ”There was an unexpected error reading input.” )
raise
else:
read_sdin(data)
if __name__ == ”__main__”:
data = [2,3,4]
read_sdin(data)
C-1.22
| Go to Top |
|
Write a short Python program that takes two arrays a and b of length n storing int values, and returns the dot product ofa and b. That is, it returns an array c of length n such that , for .
: Exercise C-1.22
”””Write a short Python program that takes two arrays a and b of length n
storing int values, and returns the dot product of a and b. That is, it returns
an array c of length n such that c[i] = a[i] ∗ b[i], for i = 0,...,n−1.
>>> dot_product([1,3,−5],[4,−2,−1])
3
>>> dot_product_array([1,3,−5],[4,−2,−1])
[4, −6, 5]
>>> dot_product([6,1,−3],[4,18,2])
36
>>> dot_product_array([6,1,−3],[4,18,2])
[24, 18, −6]
”””
def dot_product_array(a, b):
”””return an array c of length n such
that c[i] = a[i] ∗ b[i], for i = 0,...,n−1.
:param a: int vector
:param b: int vector
:return: c[i] = a[i] ∗ b[i], for i = 0,...,n−1.
”””
return [x∗y for x,y in zip(a,b)]
def dot_product(a,b):
””” The dot product between two vectors is based
on the projection of one vector onto another.
:param a: int vector
:param b: int vector
:return: sum(a[i] ∗ b[i], for i = 0,...,n−1.)
”””
return sum(dot_product_array(a,b))
C-1.23
| Go to Top |
|
Give an example of a Python code fragment that attempts to write an element to a list based on
an index that may be out of bounds. If that index is out of bounds, the program should catch the
exception that results, and print the following error message:
“Don’t try buffer overflow attacks in Python!”
: Exercise C-1.23
”””
Give an example of a Python code fragment that attempts to write an ele−
ment to a list based on an index that may be out of bounds. If that index
is out of bounds, the program should catch the exception that results, and
print the following error message:
”Don’t try buffer overflow attacks in Python!”
>>> catch_array_out_of_bounds()
Don’t try buffer overflow attacks in Python!
”””
def catch_array_out_of_bounds():
”””Exception catching example
:return: doesn’t return
”””
try:
l = []
l[0] = 1
except IndexError as ex:
print(”Don’t try buffer overflow attacks in Python!”)
C-1.24
| Go to Top |
|
Write a short Python function that counts the number of vowels in a given character string.
: Exercise C-1.24
”””
Write a short Python function that counts the number of vowels in a given
character string.
>>> count_vowels(”onomatopeya”)
{’a’: 2, ’i’: 0, ’e’: 1, ’u’: 0, ’o’: 3}
>>> count_vowels(”ONOMATOPEYA”)
{’a’: 2, ’i’: 0, ’e’: 1, ’u’: 0, ’o’: 3}
>>> count_vowels(”apple”)
{’a’: 1, ’i’: 0, ’e’: 1, ’u’: 0, ’o’: 0}
>>> count_vowels(”APPLE”)
{’a’: 1, ’i’: 0, ’e’: 1, ’u’: 0, ’o’: 0}
”””
def count_vowels(word):
”””counts the number of vowels in a given
character string.
:param word: String in which
to search vowels
:return: a Dictionary with the vowel and
times appeared
{’a’: #, ’i’: #, ’e’: #, ’u’: #, ’o’: #}
”””
counts = {}.fromkeys(”aeiou”, 0)
for char in word.lower():
if char in counts:
counts[char] += 1
return counts
C-1.25
| Go to Top |
|
Write a short Python function that takes a strings, representing a sentence, and returns a copy of
the string with all punctuation removed. For example, if given the string “Let’s try, Mike.”, this
function would return:
“Lets try Mike”.
: Exercise C-1.25
”””
Write a short Python function that takes a strings, representing a sentence,
and returns a copy of the string with all punctuation removed. For exam−
ple, if given the string ”Let s try, Mike.”, this function would return
”Lets try Mike”.
>>> strip_string(”The litte, small, tiny, cupcake... tasted delicious!”)
’The litte small tiny cupcake tasted delicious’
>>> strip_string(”struct CustomerConfig {”
...”std::string hashKey; ”
...”std::string productLine; ”
...”std::string customerNumber;”)
’struct CustomerConfig stdstring hashKey stdstring productLine stdstring customerNumber’
>>> strip_string(r’<td valign=”top” bgcolor=”#FFFFCC”>00−03</td> <td valign=”top”>.50</td><td valign=”top”>.50</td>’)
’td valigntop bgcolorFFFFCC0003td td valigntop50tdtd valigntop50td’
>>> strip_string(”Let’s try, Mike.”)
’Lets try Mike’
”””
def strip_string(sentence):
”””returns a copy of the string with all punctuation removed
:param sentence: source sentence in string form
:return: string without ’,.;:?!−_()[]∖’∖”‘/<>{}#=’
”””
punctuation_marks = r’,.;:?!−_()[]∖’∖”‘/<>{}#=’
for punctuation in punctuation_marks:
sentence = sentence.replace(punctuation, ””)
return sentence
C-1.26
| Go to Top |
|
Write a short program that takes as input three integers, , , and , from the console and determines if they can be used in a correct arithmetic formula (in the given order), like ”,” ”,” or ”.”
: Exercise C-1.26
”””
Write a short program that takes as input three integers, a, b, and c, from
the console and determines if they can be used in a correct arithmetic
formula (in the given order), like ”a+b = c,” ”a = b−c,” or ”a∗b = c.”
>>> ordered_integers(−1,3,2)
[’add’]
>>> ordered_integers(1,3,2)
[’sub’]
>>> ordered_integers(2,2,4)
[’add’, ’mul’]
>>> ordered_integers(78,78,156)
[’add’]
>>> ordered_integers(5,10,2)
[’div’]
”””
import operator
def ordered_integers(a,b,c):
””” determines if the arguments can be used
in a correct arithmetic formula (in the given
order), like ”a+b = c,” ”a = b−c,” or ”a∗b = c.”
:param a: integer
:param b: integer
:param c: integer
:return: list with operation names that
give correct arithmetic formula
”””
operator_list = [operator.add, operator.sub,
operator.mul, operator.div]
result_list = list()
for op in operator_list:
if a == op(float(b),float(c)):
result_list.append(op.__name__)
if c == op(float(a),float(b)):
result_list.append(op.__name__)
return result_list
C-1.27
| Go to Top |
|
In Section 1.8, we provided three different implementations of a generator that computes factors of a given integer. The third of those implementations, from page 41, was the most efficient, but we noted that it did not yield the factors in increasing order. Modify the generator so that it reports factors in increasing order, while maintaining its general performance advantages.
: Exercise C-1.27
”””
In Section 1.8, we provided three different implementations of a generator
that computes factors of a given integer. The third of those implementa−
tions, from page 41, was the most efficient, but we noted that it did not
yield the factors in increasing order. Modify the generator so that it reports
factors in increasing order, while maintaining its general performance ad−
vantages.
>>> for f in factors(1000):
... f
1
2
4
5
8
10
20
25
40
50
100
125
200
250
500
1000
”””
class Stack:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
return self.items[len(self.items)−1]
def size(self):
return len(self.items)
def factors(n):
”””generator that computes factors
:param n: max integer
:return: the next factor
in increasing order
”””
k = 1
ss = Stack()
while k ∗ k < n:
if n % k == 0:
yield k
ss.push(n // k)
k += 1
if k ∗ k == n:
yield k
while not ss.isEmpty():
yield ss.pop()
C-1.28
| Go to Top |
|
The p-norm of a vector
in n-dimensional space is defined as:
For the special case of , this results in the traditional Euclidean norm, which represents the length of the vector. For example, the Euclidean norm of a two-dimensional vector with coordinates has a Euclidean norm of . Give an implementation of a function named norm such that returns the p-norm value of and returns the Euclidean norm of . You may assume that is a list of numbers.
: Exercise C-1.28
”””
The p−norm of a vector v = (v_{1} ,v_{2} ,...,v_{n} )
in n−dimensional space is defined as:
||v|| = ∖sqrt[p]{vˆp_1 + vˆp_2 + ... + vˆp_n}
For the special case of p = 2, this results in the traditional
Euclidean norm, which represents the length of the vector.
For example, the Euclidean norm of a two−dimensional vector
with coordinates (4,3) has a Euclidean norm of
∖sqrt{4ˆ{2} + 3ˆ{2}} = ∖sqrt{16 + 9} = ∖sqrt{25} = 5
Give an implementation of a function named norm such that
norm(v, p) returns the p−norm value of v and norm(v) returns
the Euclidean norm of v. You may assume that vis a list of numbers.
>>> norm([4,3])
5
>>> norm([4,3,9,2],3)
9
”””
import math
def nroot(x, n):
””” Calculates the root to a given
radical n
:param x: number to which we want to find
root to n radical
:param n: radical
:return: the root
”””
return int(math.pow(x, 1.0/n))
def norm(v, p=2):
”””The p−norm of a vector v
:param v: a vector of integers
:param p: radical of the root
:return: p−norm of a vector v
”””
return nroot(sum(list(map((lambda x: x ∗∗p), v))), p)
Chapter 2
Object-Oriented Programming
The second chapter looks to provide a generic foundation on Object Orientation.
2.0.2 Exercises
The exercises in the first chapter mostly open questions.