Python Training at Intuit Bangalore - Day 1

Feb 20-22, 2017
Anand Chitipothu

These notes are available online at http://bit.ly/intuit17

© Pipal Academy LLP

Home | Day 1 | Day 2 | Day 3

In [1]:
1 + 2
Out[1]:
3
In [2]:
print("hello")
hello
In [3]:
%%file hello.py
print("hello world")
Overwriting hello.py
In [4]:
!python hello.py
hello world

Variables

In [5]:
x = 3
In [6]:
print(x)
3
In [7]:
name = "Alice"
In [8]:
print("Hello", name)
Hello Alice

In Python, variables don'y have a type. They are just placeholders which can hold any type of values.

In [9]:
x = "Python"
print("Hello", x)
Hello Python

Comments

In Python, anything starting with a # is considered a comment.

In [10]:
# this is a comment
x = 3
print(x*x)
9
In [11]:
x = x + 1 # incrementing x

Datatypes

Python has integers.

In [12]:
1 + 2
Out[12]:
3

Python has floating point numbers.

In [13]:
1.2 + 2.3
Out[13]:
3.5

Python has strings.

In [14]:
print("hello world")
hello world

Strings are enclosed either in double quotes or single quotes. Both mean the same.

In [15]:
"hello" + 'world'
Out[15]:
'helloworld'
In [16]:
"hello" * 3
Out[16]:
'hellohellohello'
In [17]:
print("=" * 40)
========================================
In [18]:
len("hello")
Out[18]:
5

Python supports the usual escape codes.

In [19]:
x = "a\nb\nc"
print(x)
a
b
c
In [21]:
x = "a\tb\tc"
print(x)
a	b	c

Python supports multi-line strings too. They need to be enclosed in three double quotes or three single quotes.

In [22]:
text = """This is a multi-line string.
Line 2
Line 3
and the text may have "quotes" too.
"""
In [23]:
print(text)
This is a multi-line string.
Line 2
Line 3
and the text may have "quotes" too.

In [24]:
text
Out[24]:
'This is a multi-line string.\nLine 2\nLine 3\nand the text may have "quotes" too.\n'

Python strings can handle non-latin text as well.

In [28]:
print("\u0c85\u0c86\u0c87\u0c88")
ಅಆಇಈ
In [29]:
kannada = "ಅಆಇಈ"
In [30]:
len(kannada)
Out[30]:
4

Python has a special type called bytes to represent binary data.

In [31]:
x = b'hello'
In [33]:
type(x)
Out[33]:
bytes
In [40]:
x = b'\x12\xc4\x70'
In [41]:
x
Out[41]:
b'\x12\xc4p'
In [43]:
hex(ord('h'))
Out[43]:
'0x68'
In [44]:
hex(ord('e'))
Out[44]:
'0x65'
In [46]:
b'\x68\x65'
Out[46]:
b'he'

Python has lists.

In [47]:
x = ["a", "b", "c"]
In [48]:
x
Out[48]:
['a', 'b', 'c']
In [49]:
x[0]
Out[49]:
'a'
In [50]:
x[1]
Out[50]:
'b'
In [51]:
len(x)
Out[51]:
3

Q: Can a list of elements of different datatypes?

absolutely!

In [52]:
x = ["a", "b", 5, [3, 4]]
In [53]:
x[3]
Out[53]:
[3, 4]
In [54]:
x[3][0]
Out[54]:
3
In [55]:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
In [56]:
matrix[2][2]
Out[56]:
9
In [57]:
print(matrix[0][0], matrix[1][0], matrix[2][0])
1 4 7
In [59]:
column0 = [matrix[0][0], matrix[1][0], matrix[2][0]]
print(column0)
[1, 4, 7]

Python has another datatype called tuple for representing fixed-width records.

In [60]:
point = (2, 3)
In [61]:
print(point)
(2, 3)
In [62]:
yellow = (255, 255, 0) # R G B
In [63]:
print(yellow)
(255, 255, 0)
In [64]:
r, g, b = yellow
print(r, g, b)
255 255 0
In [66]:
dark_yellow = (0.8 * r, 0.8 * g, 0.8 * b)
print(dark_yellow)
(204.0, 204.0, 0.0)
In [67]:
(1, 2)
Out[67]:
(1, 2)
In [68]:
1, 2
Out[68]:
(1, 2)

Python has dictionaries for representing name-value pairs.

In [69]:
person = {"name": "Alice", "email": "alice@example.com"}
In [70]:
person['name']
Out[70]:
'Alice'
In [71]:
person['email']
Out[71]:
'alice@example.com'

Q: How to represent sets in python?

Python has a set datatype too.

In [72]:
x = {1, 2, 3, 2, 1}
In [73]:
x
Out[73]:
{1, 2, 3}

Python has a boolean type. It has two special values True and False to represent truth and false.

In [75]:
True
Out[75]:
True
In [76]:
False
Out[76]:
False

Python has a special type called None to represent nothing.

In [77]:
x = None
In [78]:
print(x)
None

Variables and Strings

In [79]:
name = "Alice"
print("name")
name
In [80]:
name = Alice
print(name)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-80-01b95459c473> in <module>()
----> 1 name = Alice
      2 print(name)

NameError: name 'Alice' is not defined

The above code failed because it was looking for a variable with name Alice, instead of text "Alice".

Functions

Python has many built-in functions.

In [81]:
print("hello")
hello
In [82]:
print("hello", 1, 2, 3)
hello 1 2 3
In [83]:
len("Hello")
Out[83]:
5
In [84]:
len([1, 2, 3, 4])
Out[84]:
4

Python doesn't support operations on incompatible datatypes.

In [90]:
5 + "2"
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-90-59fb283f211c> in <module>()
----> 1 5 + "2"

TypeError: unsupported operand type(s) for +: 'int' and 'str'
In [91]:
int("2")
Out[91]:
2
In [92]:
str(2)
Out[92]:
'2'
In [93]:
5 + int("2")
Out[93]:
7
In [94]:
str(5) + "2"
Out[94]:
'52'

Example: Counting the number of digits in a number

How to count the number of digits in a number?

In [95]:
12345
Out[95]:
12345
In [96]:
2 ** 100
Out[96]:
1267650600228229401496703205376
In [97]:
2 ** 1000
Out[97]:
10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376
In [98]:
len(str(12345))
Out[98]:
5
In [99]:
len(str(2**100))
Out[99]:
31
In [100]:
len(str(2**1000))
Out[100]:
302

Writing Custom Functions

In [101]:
def square(x):
    return x*x
In [102]:
square(4)
Out[102]:
16
In [103]:
def square(x):
    y = x*x
    return y
In [104]:
a = 23
a2 = square(a)
print("square of", a, "is", a2)
square of 23 is 529

Problem: Write a function cube to compute cube of a number.

>>> cube(2)
8
>>> cube(3)
27

Problem: Write a function count_digits that takes a number as argument and returns the number of digits it has.

>>> count_digits(12345)
5
>>> count_digits(2**1000)
302
In [105]:
def square1(x):
    return x*x

def square2(x):
    print(x*x)
    
print(square1(4))
square2(4)
16
16
In [106]:
1 + square1(4)
Out[106]:
17
In [107]:
square1(square1(4))
Out[107]:
256

The square2 function is not returning anything back. The result of that is not available for using in other computations.

So, we should try to make function return values.

There may be cases where you just want to print something. It is okay not to return anything in such cases.

In [108]:
def say_hello(name):
    print("Hello", name)
In [109]:
say_hello("Python")
Hello Python

Functions are value too!

In [110]:
def square(x):
    return x*x
In [111]:
print(square(4))
16
In [112]:
print(square)
<function square at 0x11099bb70>
In [113]:
f = square
In [114]:
f(4)
Out[114]:
16
In [115]:
type(square)
Out[115]:
function
In [116]:
type(f)
Out[116]:
function
In [118]:
print(f)
<function square at 0x11099bb70>

Is there any practical value for this feature? Let us see an example.

In [119]:
def square(x):
    return x*x

def sum_of_squares(x, y):
    return square(x) + square(y)

print(sum_of_squares(3, 4))
25
In [120]:
def cube(x):
    return x*x*x

def sum_of_cubes(x, y):
    return cube(x) + cube(y)

print(sum_of_cubes(3, 4))
91

Both sum_of_squares and sum_of_cubes are doing almost the same thing. Can we generalize both of them into a single function?

In [121]:
def sumof(f, x, y):
    return f(x) + f(y)
In [122]:
sumof(square, 3, 4)
Out[122]:
25
In [123]:
sumof(cube, 3, 4)
Out[123]:
91
In [124]:
sumof(len, "hello", "python")
Out[124]:
11

This feature is so useful that even some built-in functions take functions as arguments.

In [127]:
max(3, 4)
Out[127]:
4

It can even be called with a list of values.

In [128]:
max([3, 4])
Out[128]:
4
In [130]:
max(["one", "two", "three", "four", "five"])
Out[130]:
'two'
In [131]:
"python" > "perl"
Out[131]:
True
In [132]:
"python" > "java"
Out[132]:
True
In [133]:
"man" > "woman"
Out[133]:
False

The string comparison uses the dictionary ordering.

How to find the longest word?

In [134]:
max(["one", "two", "three", "four", "five"], key=len)
Out[134]:
'three'
In [136]:
min(["one", "two", "three", "four", "five"], key=len)
Out[136]:
'one'
In [137]:
# records of students with name and marks
records = [
    ("A", 78),
    ("B", 96),
    ("C", 64)
]

Find the record with maximum marks.

In [138]:
def get_marks(record):
    return record[1]
In [139]:
max(records, key=get_marks)
Out[139]:
('B', 96)

Methods

Methods are special kind of functions that work on an object.

In [140]:
x = "Hello"
In [141]:
x.upper()
Out[141]:
'HELLO'
In [142]:
x.lower()
Out[142]:
'hello'
In [143]:
"mathematics".count("mat")
Out[143]:
2
In [144]:
"mathematics".replace("mat", "rat")
Out[144]:
'ratheratics'

Problem Write a function count_zeros to count the number of zeros in the given number.

>>> count_zeros(0)
1
>>> count_zeros(100)
2
>>> count_zeros(2030405)
3
In [145]:
def count_zeros(n):
    # FIX ME
    return 0

print(count_zeros(0))
print(count_zeros(100))
print(count_zeros(2030405))
0
0
0
In [151]:
def count_zeros(n):
    return str(n).count('0')

print(count_zeros(0))
print(count_zeros(100))
print(count_zeros(2030405))
1
2
3

Let us look at some more useful methods on strings.

In [146]:
sentence = "Anything that can go wrong, will go wrong"
In [147]:
sentence.split()
Out[147]:
['Anything', 'that', 'can', 'go', 'wrong,', 'will', 'go', 'wrong']

The split method splits on any whitespace by default.

Optionally, we can specify a delimiter.

In [148]:
sentence.split(",")
Out[148]:
['Anything that can go wrong', ' will go wrong']

The join method does the reverse of split.

In [149]:
",".join(['one', 'two', 'three'])
Out[149]:
'one,two,three'
In [150]:
"--".join(['one', 'two', 'three'])
Out[150]:
'one--two--three'

Problem: Write a function count_words that takes a sentence as argument and returns the number of words it has.

>>> count_words("life is suffering")
3

Problem: Write a function longest_word that takes a sentence as argument and returns the longest word from it.

>>> longest_word("one two three four five")
'three'

Modules

In [152]:
import time
In [153]:
print(time.asctime())
Mon Feb 20 13:35:03 2017

The import statement imports a module and allows us to call functions defined in that.

The import is also like an assignment.

In [155]:
time
Out[155]:
<module 'time' (built-in)>
In [156]:
t = time
print(t.asctime())
Mon Feb 20 13:38:31 2017

We can also import some functions defined in a module.

In [154]:
from time import asctime
print(asctime())
Mon Feb 20 13:37:46 2017

Let us look at some interesting modules in Python.

The os module

In [157]:
import os
In [158]:
# get the current working directory
os.getcwd()
Out[158]:
'/Users/anand/trainings/2017/intuit'
In [159]:
# all files in the current directory
os.listdir(".")
Out[159]:
['.hello.py.swp',
 '.ipynb_checkpoints',
 'Makefile',
 'Untitled.html',
 'day1.html',
 'day1.ipynb',
 'hello.py',
 'index.html',
 'index.ipynb',
 'push']

Problem: Write a function count_files that takes path to a directory as argument and returns the number of files it has.

>>> count_files(".")
10
>>> count_files("/tmp")
15
In [161]:
def count_files(path):
    files = os.listdir(path)
    return len(files)

print(count_files("."))
print(count_files("/tmp"))
10
8

How to find the file size?

In [162]:
os.path.getsize("hello.py")
Out[162]:
20

How to find the largest file in the current directory?

In [163]:
max(os.listdir("."), key=os.path.getsize)
Out[163]:
'day1.html'

Help! Help!! Help!!!

In [164]:
help(os.path.getsize)
Help on function getsize in module genericpath:

getsize(filename)
    Return the size of a file, reported by os.stat().

In [165]:
help("os.path.getsize")
Help on function getsize in os.path:

os.path.getsize = getsize(filename)
    Return the size of a file, reported by os.stat().

If you are on unix, you can use command pydoc.

$ pydoc os.path.getsize

How to list all functions etc. defined in a module?

The built-in function dir returns all the variables defined in a module.

In [169]:
dir(time)
Out[169]:
['_STRUCT_TM_ITEMS',
 '__doc__',
 '__loader__',
 '__name__',
 '__package__',
 '__spec__',
 'altzone',
 'asctime',
 'clock',
 'ctime',
 'daylight',
 'get_clock_info',
 'gmtime',
 'localtime',
 'mktime',
 'monotonic',
 'perf_counter',
 'process_time',
 'sleep',
 'strftime',
 'strptime',
 'struct_time',
 'time',
 'timezone',
 'tzname',
 'tzset']
In [170]:
help("time.localtime")
Help on built-in function localtime in time:

time.localtime = localtime(...)
    localtime([seconds]) -> (tm_year,tm_mon,tm_mday,tm_hour,tm_min,
                              tm_sec,tm_wday,tm_yday,tm_isdst)
    
    Convert seconds since the Epoch to a time tuple expressing local time.
    When 'seconds' is not passed in, convert the current time instead.

The random module

In [171]:
import random
In [174]:
random.choice(["one", "two", "three", "four", "five"])
Out[174]:
'three'

How to generate a random word from a sentence?

In [175]:
def random_word(sentence):
    return random.choice(sentence.split())
In [178]:
random_word("one two three four five")
Out[178]:
'three'
In [179]:
random_word("life is random")
Out[179]:
'life'
In [183]:
random_word("the sooner you start to code, the longer it takes")
Out[183]:
'the'

Let us try a fun program.

Write a function say_hello to say hello in a random language.

In [188]:
def say_hello(name):
    prefix_options = ["Hello", "Namaskara", "Ola", "Namaskaram", "Lal Salam"] 
    prefix = random.choice(prefix_options)
    print(prefix, name)
In [189]:
say_hello("Python")
Namaskaram Python
In [191]:
say_hello("Python")
Lal Salam Python

Can we improve the above function to have both a prefix and suffix, like shown below:

Namaskar Gopal Ji
Namaskaram Gopal Garu
Namaskara Gopal avure
Ram Ram Gopal Sahib
In [192]:
def say_hello(name):
    prefix, suffix = get_random_greeting()
    print(prefix, name, suffix)
    
def get_random_greeting():
    # FIX ME
    return "Namaskaram", "Garu"

say_hello("Gopal")
Namaskaram Gopal Garu
In [193]:
def say_hello(name):
    prefix, suffix = get_random_greeting()
    print(prefix, name, suffix)
    
def get_random_greeting():
    options = [
        ("Namaskaram", "garu"),
        ("Namaskara", "avure"),
        ("Ram ram", "sahib"),
        ("Namaskar", "Ji")        
    ]
    return random.choice(options)

say_hello("Gopal")
Ram ram Gopal sahib

Reading Command-line arguments

The sys module keeps in the command-line arguments in a special variable argv.

In [194]:
%%file args.py
import sys
print(sys.argv)
Writing args.py
In [195]:
!python args.py
['args.py']
In [196]:
!python args.py hello world
['args.py', 'hello', 'world']

By convention, the first element in that list is always the program name.

In [197]:
!python args.py 1 2 3 4 5
['args.py', '1', '2', '3', '4', '5']

Remember that the arguments are always strings.

Example: echo.py

Let us write a program to print the first command-line argument.

In [200]:
%%file echo.py
import sys
print(sys.argv[1]) 
Overwriting echo.py
In [201]:
!python echo.py hello
hello
In [202]:
!python echo.py hello world
hello

Problem: Write a program square.py that takes a number as command-line argument and prints its square.

$ python square.py 4
16

Problem: Write a program add.py that takes two numbers as command-line arguments and prints their sum.

$ python add.py 2 3
5
$ python add.py 5 4
9
In [209]:
%%file square.py
import sys
#print(sys.argv)
x = int(sys.argv[1])
print(x*x)
Overwriting square.py
In [210]:
!python square.py 4
16

Conditional Expressions

In [211]:
score = 47
In [212]:
score > 30
Out[212]:
True
In [213]:
score < 50
Out[213]:
True
In [214]:
name = "Alice"
In [215]:
name == "Alice"
Out[215]:
True
In [216]:
name == "Alice" and score > 30
Out[216]:
True

The in operator can be used to check if an element is part of another.

In [217]:
"hell" in "hello"
Out[217]:
True
In [219]:
"yell" in "hello"
Out[219]:
False
In [220]:
"yell" not in "hello"
Out[220]:
True
In [221]:
"a" in ["a", "b", "c", "d"]
Out[221]:
True
In [222]:
vowels = ["a", "e", "i", "o", "u"]
def is_vowel(c):
    return c in vowels
In [223]:
is_vowel('a')
Out[223]:
True
In [224]:
is_vowel('x')
Out[224]:
False

Strings have other useful methods to check for prefix and suffix matching.

In [225]:
"hello".startswith("hell")
Out[225]:
True
In [226]:
"hello".endswith("lo")
Out[226]:
True
In [227]:
def is_python_file(filename):
    return filename.endswith(".py")
In [228]:
is_python_file("hello.py")
Out[228]:
True
In [229]:
is_python_file("hello.java")
Out[229]:
False
In [ ]: