Python 3home |
Given a list of numbers, sum them up using a linear approach and using recursion. Answers appear on next slide.
Given a list of numbers, sum them up using a linear approach and using recursion. linear approach
def list_sum_linear(num_list):
the_sum = 0
for i in num_list:
the_sum = the_sum + i
return the_sum
print(list_sum([1,3,5,7,9]))
recursion approach
def list_sum_recursive(num_list):
if len(num_list) == 1:
return num_list[0]
else:
return num_list[0] + list_sum_recursive(num_list[1:])
print(list_sum_recursive([1,3,5,7,9]))
This was a question in an interview at AppNexus that I helped conduct, calling for a Python ETL developer (extract, transform, load) -- not a high-end position, but still one of value (and significant remuneration). Answers appear on next slide. Class and STDOUT data stream
class OT(object):
def __init__(self, *thisfile):
self.file = thisfile
def write(self, obj):
for f in self.file:
f.write(obj)
sys.stdout = OT(sys.stdout, open('myfile.txt'))
1. What does this code do? Feel free to talk it through 2. What is the 'object' in the parentheses? 3. What does the asterisk in *thisfile mean? local and global namespace
var = 10
def myfunc():
var = 20
print(var)
myfunc()
print(var)
1. What will this code output? Why? "sort" functions and multidimensional structures
def myfunc(arg):
return arg
struct = [ { 'a': [1, 2, 3], 'b': [4, 5, 6], 'c': [7, 8, 9] }, { 'a': [10, 12, 13], 'b': [1, 2, 3], 'c': [1, 2, 3] }, { 'a': [1, 2, 3], 'b': [1, 2, 3], 'c': [1, 2, 3] } ]
dd = sorted(struct, key=myfunc)
1. What type of object is arg? 2. Rewrite the 'myfunc' function so the dicts are sorted by the sum of values associated with 'c'. 3. Convert your 'myfunc' function as a lambda 4. Loop through struct and print out just the last value of each list. import statements 1. which of these import statements do you favor and why?
import datetime
import datetime as dt
from datetime import *
Class and STDOUT data stream
class OT(object):
def __init__(self, *thisfile):
self.file = thisfile
def write(self, obj):
for f in self.file:
f.write(obj)
sys.stdout = OT(sys.stdout, open('myfile.txt', 'w'))
1. What does this code do? Feel free to talk it through. The class creates an object that stores multiple open data streams (in this case, sys.stdout and an open filehandle) in an attribute of the instance. When the write() method is called on the object, the class will write to each of the stream(s) initialized in the instance, in this case to sys.stdout() and to the open file. The OT instance is being assigned to sys.stdout. This means that any call to sys.stdout.write() will pass to the instance. In addition, the print statement will also call sys.stdout.write(). The effect of this code is for any print statements that occur afterward to write to both STDOUT and to the filehandle initialized when the instance was constructed. 2. What is the 'object' in the parentheses? It causes the OT class to inherit from object. Thus OT is a new-style class. 3. What does the asterisk in *thisfile mean? It allows any number of arguments to be passed to the constructor / to __init__. local and global namespace
var = 10
def myfunc():
var = 20
print(var)
myfunc()
print(var)
1. What will this code output? Why? 20 10 Inside myfunc() the local variable var is set to 20 and printed. Once returned from the function, the global var is "revealed" (i.e., it is now accessible under the name var. "sort" functions and multidimensional structures
def myfunc(arg):
return arg
struct = [ { 'a': [1, 2, 3], 'b': [4, 5, 6], 'c': [7, 8, 9] }, { 'a': [10, 12, 13], 'b': [1, 2, 3], 'c': [1, 2, 3] }, { 'a': [1, 2, 3], 'b': [1, 2, 3], 'c': [1, 2, 3] } ]
dd = sorted(struct, key=myfunc)
1. What type of object is arg? arg is a string, or a key from the dict. 2. Rewrite the 'myfunc' function so the dicts are sorted by the sum of values associated with 'c'. def myfunc(arg): return sum(myfunc(arg)) 3. Convert your 'myfunc' function as a lambda lambda arg: sum(myfunc(arg)) 4. Loop through struct and print out just the last value of each list. for key in struct: print(struct[key][-1]) import statements 1. which of these import statements do you favor and why?
import datetime
import datetime as dt
from datetime import *
The answer should see the candidate disavowing any use of the last form, which imports all symbols from the datetime module into the global namespace, and thus risks collisions with other modules
A factorial is the multiplication of each integer in a consecutive range starting at 0. So 4 factorial is 1 * 2 * 3 * 4 = 24. In the recursive approach, the function's job is very simply to multiply the number passed to it by the product produced by another call to the function with a number one less than the one passed to it. The function thus continues to call itself with one less integer until the argument becomes 0, at which point it returns. As each recursively called function returns, it passes back the value it was passed, multiplied by the value passed to it. So on the way back the values are multiplied. Answers appear on next slide.
factorial: "linear" approach
def factorial_linear(n):
prod = 1
for i in range(1, n+1):
prod = prod * i
return prod
factorial: "recursion" approach
def factorial_recursive(n):
if n < 1:
return 1
else:
return_number = n * factorial_recursive(n-1) # recursive call
print('{}! = {}'.format(n, return_number))
return return_number
A fibonacci series is one in which each number is the sum of the two previous numbers. Answers appear on next slide.
A fibonacci series is one in which each number is the sum of the two previous numbers. linear approach
def fib_lin(max):
prev = 0
curr = 1
while curr < max:
print(curr, end=' ')
newcurr = prev + curr
prev = curr
curr = newcurr
Answers appear on next slide.
def get_primes(maxval):
startval = 2
while startval <= maxval:
counter = 2
while counter < startval:
if startval % counter == 0:
startval = startval + 1
counter = 2
continue
else:
counter = counter + 1
continue
print(startval)
startval = startval + 1
this_list = ['a', 'b', 'c', 'd', 'e']
Answers appear on next slide.
this_list = ['a', 'b', 'c', 'd', 'e']
# using reversed
print(list(reversed(this_list)))
# using sorted
print(sorted(this_list, reverse=True))
# using negative stride
print(this_list[::-1])
# using list.insert()
newlist = []
for el in this_list:
newlist.insert(0 ,el)
# using indices
newlist = []
index = len(this_list)-1
while index >= 0:
newlist.append(this_list[index])
index = index - 1
Answers appear on next slide.
def ispalindrome(test1, test2):
test2 = list(test2)
for char in test1:
try:
test2.remove(char)
except ValueError:
return False
if test2:
return False
return True
str1 = 'allabean'
str2 = 'beallana'
print(ispalindrome('allabean', 'beallana'))
print(ispalindrome('allabean', 'beallaaa'))
Answers appear on next slide.
test_string = 'Able was I ere I saw Elba'
if test_string.lower() == test_string.lower()[::-1]:
print('"{}" is a palindrome'.format(test_string))
These really are unfair, and not necessarily a good barometer -- they simply require that you know the quirks that lead to the strange output. But they can point out interesting aspects of the language. Answers appear on next slide. for each of the following blocks of code, what is the output?
def extendList(val, list=[]):
list.append(val)
return list
list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList('a')
print("list1 = %s" % list1)
print("list2 = %s" % list2)
print("list3 = %s" % list3)
def multipliers():
return [lambda x : i * x for i in range(4)]
print([m(2) for m in multipliers()])
class Parent(object):
x = 1
class Child1(Parent):
pass
class Child2(Parent):
pass
print(Parent.x, Child1.x, Child2.x)
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)
def div1(x,y):
print("%s/%s = %s" % (x, y, x/y))
def div2(x,y):
print("%s//%s = %s" % (x, y, x//y))
div1(5,2)
div1(5.,2)
div2(5,2)
div2(5.,2.)
1. list = [ [ ] ] * 5 2. list # output? 3. list[0].append(10) 4. list # output? 5. list[1].append(20) 6. list # output? 7. list.append(30) 8. list # output?
for each of the following blocks of code, what is the output?
def extendList(val, list=[]):
list.append(val)
return list
list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList('a')
print("list1 = %s" % list1)
print("list2 = %s" % list2)
print("list3 = %s" % list3)
# [10, 'a']
# [123]
# [10, 'a']
default list is constructed at time of definition
def multipliers():
return [lambda x : i * x for i in range(4)]
print([m(2) for m in multipliers()])
# [6, 6, 6, 6]
Python closures are late binding, means that when we finally call the function it will look up the value of i and find a 6
class Parent(object):
x = 1
class Child1(Parent):
pass
class Child2(Parent):
pass
print(Parent.x, Child1.x, Child2.x)
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)
## 1 1 1
## 1 2 1
## 3 2 3
Attribute lookup starts in instance, then checks class and then parent class(es).
def div1(x,y):
print("%s/%s = %s" % (x, y, x/y))
def div2(x,y):
print("%s//%s = %s" % (x, y, x//y))
div1(5,2)
div1(5.,2)
div2(5,2)
div2(5.,2.)
## 2
## 2.5
## 2
## 2
"floor division" (i.e., integerized result) is the default with integer operands; also can be specified with the // "floor division" operator
1. list = [ [ ] ] * 5 2. list # output? 3. list[0].append(10) 4. list # output? 5. list[1].append(20) 6. list # output? 7. list.append(30) 8. list # output? ## [[], [], [], [], []] ## [[10], [10], [10], [10], [10]] ## [[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]] ## [[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30]
key: in a * multiplication, Python simply duplicates the reference rather than the list