Feb 20-22, 2017
Anand Chitipothu
These notes are available online at http://bit.ly/intuit17
© Pipal Academy LLP
if Statement¶n = 35
if n % 2 == 0:
print("even")
else:
print("odd")
def check_even(n):
if n % 2 == 0:
print("even")
else:
print("odd")
check_even(4)
check_even(5)
Checking multiple conditions can be done using elif statements.
def check_number(n):
if n < 10:
print(n, "is a single digit number")
elif n < 100:
print(n, "is a two digit number")
else:
print(n, "is a big number")
check_number(3)
check_number(54)
check_number(267)
Problem: Write a function minimum to compute the minimum of two numbers, without using the built-in function min. Please note that the function should return a value, not print.
>>> minimum(3, 7)
3
>>> minimum(33, 7)
7
>>> 1 + minimum(3, 7)
4
>>> 1 + minimum(3, 3)
4
Problem: Write a function minimum3 to compute minimum of three numbers. Can you do this by using the minimum function defined above?
>>> minimum3(2, 3, 4)
2
>>> minimum3(12, 3, 4)
3
>>> minimum3(12, 13, 4)
4
def minimum(x, y):
if x < y:
return x
else:
return y
print(minimum(3, 7))
print(minimum(33, 7))
print(1+minimum(3, 7))
print(1+minimum(3, 3))
def minimum3(x, y, z):
a = minimum(x, y)
if a < z:
return a
else:
return z
print(minimum3(2, 3, 4))
print(minimum3(12, 3, 4))
print(minimum3(12, 13, 4))
def minimum3(x, y, z):
a = minimum(x, y)
return minimum(a, z)
print(minimum3(2, 3, 4))
print(minimum3(12, 3, 4))
print(minimum3(12, 13, 4))
def minimum3(x, y, z):
return minimum(minimum(x, y), z)
print(minimum3(2, 3, 4))
print(minimum3(12, 3, 4))
print(minimum3(12, 13, 4))
x = ["a", "b", "c", "d"]
len(x)
x[0]
x[1]
x = ["a", "b", "c", "d"]
for value in x:
print(value)
names = ["Alice", "Bob", "Charlie", "Dave"]
for name in names:
print(name)
for name in names:
print("Hello", name)
How to print all words in a sentence?
sentence = "when in doubt, use brute force"
for word in sentence.split():
print(word)
Problem: Write a program ls.py that takes path to a directory as command-line argument and prints all the files in that directory. The output should contain one filename per line.
$ python ls.py .
Makefile
day1.ipynb
day1.html
hello.py
Hint: see os.listdir
Python has a built-in function range to iterate over sequence of numbers.
for i in range(5):
print(i)
range(5) gives values from 0 to 4.
for i in range(2, 5):
print(i)
# say hello n times
def say_hello(name, n):
for i in range(n):
print("Hello", name)
say_hello("Everyone", 4)
Python has a built-in function sum to compute sum of a list of numbers.
sum([1, 2, 3, 4, 5])
sum(range(10))
sum(range(1000000))
Let us try to implement our own sum function.
def my_sum(numbers):
result = 0
print("result =", result)
for n in numbers:
result = result + n
print("n =", n, "result =", result)
return result
print(my_sum([10, 20, 30, 40, 50]))
# print(my_sum(range(10)))
# print(my_sum(range(1000000)))
Problem: Write a function product to compute product of given list of numbers.
>>> product([1, 2, 3, 4])
24
Problem: Write a function factorial that takes a number as argument and computes its factorial. Can you use the above implementation of product in computing it?
>>> factorial(4)
24
def product(numbers):
result = 1
for n in numbers:
result = result * n
return result
print(product([10, 20, 30, 40]))
def factorial(n):
numbers = range(1, n+1)
return product(numbers)
factorial(4)
factorial(0)
factorial(5)
1*2*3*4*5
x = ["a", "b", "c", "d"]
x
x[1]
x[1] = 'bb'
x
x.append('e')
x
Notice that the append method doesn't return anything, but modifies the list in-place.
Let us write a function squares to compute squares of all numbers in a list.
def squares(numbers):
result = []
for n in numbers:
result.append(n*n)
return result
print(squares([10, 20, 30, 40]))
print(squares(range(10)))
# sum of squares of all numbers below one million
sum(squares(range(1000000)))
Problem: Write a function evens that takes a list of numbers as argument and returns a new list containing only the even numbers out of them.
>>> evens([1, 2, 3, 4, 5, 6])
[2, 4, 6]
x = [1, 2, 3, 4, 5, 6]
[a*a for a in x]
[a*a for a in x if a%2 == 0]
names = ["a", "b", "c", "d"]
uppernames = [name.upper() for name in names]
uppernames
Problem: Write a function list_pyfiles that takes path to a directory as argument and returns all the python files in that directory.
>>> list_pyfiles(".")
['echo.py', 'square.py', ...]
List comprehensions are used to transform one list to another.
They are usually in the following form:
[expr for var in alist]
[expr for var in alist if some_cond]
import os
def list_pyfiles(path):
return [f for f in os.listdir(path) if f.endswith(".py")]
list_pyfiles(".")
How to find total size of all python files in the current directory?
[f for f in os.listdir(".") if f.endswith(".py")]
[os.path.getsize(f) for f in os.listdir(".") if f.endswith(".py")]
sum([os.path.getsize(f) for f in os.listdir(".") if f.endswith(".py")])
x = ['a', 'b', 'c', 'd']
for a in x:
print(a)
x = ['a', 'b', 'c', 'd']
for a in x:
print(a, a.upper())
[a.upper() for a in x]
for i in range(5):
print(i)
for i in range(2, 5):
print(i, i*i)
[i*i for i in range(10)]
names = ["a", "b", "c", "d"]
scores = [10, 20, 30, 40]
zip(names, scores)
list(zip(names, scores))
for name, score in zip(names, scores):
print(name, score)
for pair in zip(names, scores):
print(pair)
# since pair is a tuple of two elements,
# we can assign that to two different variables.
for pair in zip(names, scores):
name, score = pair
print(name, score)
# When we use two variables in the for loop, thats what is done implicitly.
for name, score in zip(names, scores):
print(name, score)
Problem: Write a function vector_add to add two vectors.
>>> vector_add([1, 2, 3, 4], [10, 20, 30, 40])
[11, 22, 33, 44]
def vector_add(A, B):
return [a+b for a, b in zip(A, B)]
vector_add([1, 2, 3, 4], [10, 20, 30, 40])
names = ["a", "b", "c", "d"]
for i, name in enumerate(names):
print(i, name)
list(enumerate(names))
Let us look at a simple example.
chapters = ["Getting started", "Lists", "Working with Files"]
for i, title in enumerate(chapters):
print("chapter", i+1, ":", title)
for i, title in enumerate(chapters, start=1):
print("chapter", i, ":", title)
x = ["a", "b", "c", "d"]
x[0]
x[1]
How to get the last element of x?
x[len(x)-1]
x[-1] # last element
x[-2] # second last element
Let us try an example.
def get_last_word(sentence):
return sentence.split()[-1]
get_last_word("one two three")
Problem: Write a function getext to find the extension of given filename.
>>> getext("a.py")
'py'
>>> getext("a.tar.gz")
'gz'
Assume that the filename will always have an extension.
x = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
x[0:2]
x[:2] # upto index 2 (2 is not included)
x[2:] # index 2 onwards
x[2:6] # from index 2 to index 6
x[1:6:2] # take every second element start from index 1 to 6
x[:] # copy of x
x[::-1] # reverse of the list
x[:-1] # all, but not the last element
Earlier we wrote a program echo.py to print the first command-line argument. Let us improve that to print all command-line arguments.
%%file echo2.py
import sys
#print(sys.argv)
args = sys.argv[1:] # skip the program name
#print(args)
print(" ".join(args))
!python echo2.py hello world
!python echo2.py hello world hello everyone
Problem: Write a program sum.py that takes multiple numbers as command-line arguments and prints their sum.
$ python sum.py 1 2 3
6
$ python sum.py 1 2 3 4 5
15
%%file sum.py
import sys
print(sys.argv)
args = sys.argv[1:]
print(args)
numbers = [int(a) for a in args]
print(numbers)
print(sum(numbers))
!python sum.py 1 2 3
%%file sum.py
import sys
args = sys.argv[1:]
numbers = [int(a) for a in args]
print(sum(numbers))
!python sum.py 1 2 3
%%file sum.py
import sys
print(sum([int(a) for a in sys.argv[1:]]))
!python sum.py 1 2 3 4 5
%%file mymodule.py
print("begin mymodule")
x = 1
def add(a, b):
return a+b
print(add(3, 4))
print("end mymodule")
!python mymodule.py
%%file a.py
print("before import")
import mymodule
print("after import")
print(mymodule.x)
print(mymodule.add(10, 20))
!python a.py
__name__ special variable¶%%file mymodule2.py
x = 1
def add(a, b):
return a+b
print(add(3, 4))
print(__name__)
!python mymodule2.py
!python -c "import mymodule2"
When the file is executed as a script, the value of __name__ is set to "__main__". When the file is imported as a module, it is set to the module name.
%%file mymodule3.py
x = 1
def add(a, b):
return a+b
if __name__ == "__main__":
# Run the following code only when this file is
# executed as a script.
# Ignore this when this file is imported as a module.
print(add(3, 4))
!python mymodule3.py
!python -c "import mymodule3"
%%file square.py
"""The square module.
The long description of the module.
copyright: blah blah blah
"""
import sys
def square(x):
"""Computes square of a number.
>>> square(4)
16
"""
return x*x
def main():
n = int(sys.argv[1])
print(square(n))
if __name__ == "__main__":
main()
!python square.py 6
import square
print(square.square(8))
help(square)
Problem: Write cube module.
Note: You'll have to install third-party module py.test to do the following. Instructions will be provided at the end.
def square(x):
return x*x
print(square(3))
It is hard to know if the output is correct or not. A better way would be to test for correct value.
if square(3) == 9:
print("TEST PASSED")
Python has an assert statement to test for things.
def test_square():
assert square(0) == 0
assert square(3) == 9
assert square(-3) == 90
test_square()
There are some tools to make running tests easier.
%%file sq.py
def square(x):
return x*x
def sum_of_squares(x, y):
return square(x) + square(y)
def test_square():
assert square(0) == 0
assert square(3) == 9
assert square(-3) == 90
def test_sum_of_squares():
assert sum_of_squares(0, 0) == 0
assert sum_of_squares(3, 4) == 25
!py.test sq.py
py.test finds all functions starting with "test" prefix and executes each one of them.
!py.test sq.py -v
Q: Is there way to run tests selectively?
!py.test -k test_square -v sq.py
Python comes with a tool called pip (pip3 for python3) install third-party packages.
pip3 install pytest
!pip3 install pytest
names = ["alice", "dave", "bob", "charlie"]
names.sort() # sorts the list in-place.
names
Notice that the sort method modifies the list and doesn't return anything.
names = ["alice", "dave", "bob", "charlie"]
sorted(names) # returns a new sorted list
How to sort these names by length?
sorted(names, key=len)
How to sort ignoring the case?
names = ["Alice", "bob", "dave", "Charlie"]
sorted(names)
# this is not what we need
sorted([name.lower() for name in names])
def ignore_case(name):
print("ignore_case", name)
# FIXME
return name.lower()
sorted(names, key=ignore_case)
Problem: Print all files in the current directory, sorted by the file size.
x = "hello"
x[0]
for c in x:
print(c)
max("helloworld")
x
x[:4]
We can use the strip method to remove any characters from both ends of a string.
" hello \n".strip() # strip any white space
" hello \n".strip("\n") # strip new line
name = "Python"
message = "Hello {}!".format(name)
print(message)
"chapter {}: {}".format(1, "Getting Started")
Sometimes we may want to use the same value multiple times.
t = "chapter {}: {}\nThe contents of {} will come here"
print(t.format(1, "Getting Started", "Getting Started"))
Instead of specifying multiple times, we can use index.
t = "chapter {0}: {1}\nThe contents of {1} will come here"
print(t.format(1, "Getting Started"))
It is also possible to specify the values by name.
t = "chapter {index}: {title}\nThe contents of {title} will come here"
print(t.format(index=1, title="Getting Started"))
x = "Getting Started"
t = "chapter {index}: {title}\nThe contents of {title} will come here"
print(t.format(index=1, title=x))
Let us look at a simple example.
def make_link(url):
return '<a href="{url}">{url}</a>'.format(url=url)
make_link("http://google.com")
Python also supports a legacy string formatting.
print("hello %s" % "Python")