Understanding The Stack
Understanding The Stack
of Contents
About
1.1
Introduction
1.2
1.3
Functions
1.4
1.5
1.6
Control Structures
1.7
Lists
1.8
1.9
Text Processing
1.10
File handling
1.11
1.12
1.13
Docstrings
1.14
Further Reading
1.15
About
Python Basics
Introduction to Python - Syntax, working with Shell commands, Files, Text
Processing, and more...
Content here is for a one-day workshop for Python beginners
Python curated resources for more complete resources list, including tutorials
for beginners
For more related resources, visit scripting course
Chapters
Introduction
Installation, Hello World example, Python Interpreter, Python Standard
Library
Number and String data types
Numbers, String, Constants, Built-in Operators
Functions
def, print function, range function, type function, Variable Scope
Getting User input
Integer input, Floating point input, String input
Executing external commands
Calling Shell commands, Calling Shell commands with expansion,
Getting command output and redirections
Control Structures
Condition checking, if, for, while, continue and break
Lists
Assigning List variables, Slicing and Modifying Lists, Copying Lists, List
Methods and Miscellaneous, Looping, List Comprehension
Sequence, Set and Dict data types
Strings, Tuples, Set, Dictionary
Text Processing
About
String methods, Regular Expressions, Pattern matching and extraction,
Search and Replace, Compiling Regular Expressions, Further Reading
on Regular Expressions
File handling
open function, Reading files, Writing to files
Command line arguments
Known number of arguments, Varying number of arguments, Using
program name in code, Command line switches
Exception Handling and Debugging
Exception Handling, Syntax check, pdb, Importing program
Docstrings
Style guide, Palindrome example
Further Reading
Standard topics not covered, Useful links on coding, Python extensions
ebook
Read as ebook on gitbook
Download ebook for offline reading - link
Credits
Devs and Hackers - helpful slack group
Weekly Coders, Hackers & All Tech related thread - for suggestions and
critique
/r/learnpython/ - helpful forum for beginners and experienced programmers
alike
License
3
About
This work is licensed under a Creative Commons Attribution-NonCommercialShareAlike 4.0 International License
Introduction
Introduction
Installation
Hello World example
Python Interpreter
Python Standard Library
From wikipedia)
Python is a widely used high-level, general-purpose, interpreted, dynamic
programming language. Its design philosophy emphasizes code readability,
and its syntax allows programmers to express concepts in fewer lines of code
than possible in languages such as C++ or Java. The language provides
constructs intended to enable clear programs on both a small and large scale
Guido van Rossum is the author of Python programming language, and continues
to oversee the Python development process
Installation
Get Python for your OS from official website - https://www.python.org/
Examples presented here is for Unix-like systems, Python version 3 and
uses bash shell
You can also run Python code online
pythontutor - code execution in Python 2 and 3 versions, visualizing code
flow and sample programs are among its features
jupyter - web application that allows you to create and share documents
that contain live code, equations, visualizations and explanatory text
ideone - online compiler and debugging tool which allows you to compile
source code and execute it online in more than 60 programming
languages
Python Interpreter shell
It is assumed that you are familiar with command line. If not, check out this
Introduction
basic tutorial on ryanstutorials and this list of curated resources for Linux
path provided
The third line prints the message Hello World with a newline character added
by default by the print function
Running Python program
You can write the program using text editor like gedit, vim or other editors
After saving the file, give execute permission and run the program from a terminal
$ chmod +x hello_world.py
$ ./hello_world.py
Hello World
Introduction
If you happen to follow a book/tutorial on Python version 2 or coming with Perl
experience, it is a common mistake to forget () with print function
#!/usr/bin/python3
print "Have a nice day"
Depending on type of error, it may be easy to spot the mistake based on error
messages printed on executing the program
In this example, we get the appropriate Missing parentheses message
$ ./syntax_error.py
File "./syntax_error.py", line 3
print "Have a nice day"
^
SyntaxError: Missing parentheses in call to 'print'
Further Reading
Python docs - version 3
Different ways of executing Python programs
Where is Python used?
Python docs - Errors and Exceptions
Common syntax errors
Python Interpreter
7
Introduction
It is generally used to execute snippets of Python language as a means to
learning Python or for debugging purposes
The prompt is usually >>>
Some of the topics in coming chapters will be complemented with examples
using the Python Interpreter
A special variable _ holds the result of last printed expression
One can type part of command and repeatedly press Up arrow key to match
commands from history
Press Ctrl+l to clear the screen, keeping any typed command intact
exit() to exit
$ python3
Python 3.4.3 (default, Oct 14 2015, 20:28:29)
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more inform
ation.
>>> print("hi")
hi
>>> abc
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'abc' is not defined
>>> num = 5
>>> num
5
>>> 3 + 4
7
>>> 12 + _
19
>>> exit()
Further Reading
Python docs - Using the Python Interpreter
Python docs - Interpreter example
Introduction
Numbers
Integer examples
>>> num1 = 7
>>> num2 = 42
>>> sum = num1 + num2
>>> print(sum)
49
>>> sum
49
>>> 34 ** 32
10170102859315411774579628461341138023025901305856
>>> 9 / 5
1.8
>>> 9 // 5
1
>>> 9 % 5
4
10
>>> appx_pi = 22 / 7
>>> area = 42.16
>>> appx_pi + area
45.30285714285714
>>> num1
7
>>> num1 + area
49.16
Further Reading
Python docs - numbers
decimal
fractions
complex
Python docs - keywords - do not use these as variables
11
String
strings can be declared using single or double quotes
Use \ to escape quotes which are part of string itself if the string contains
both single and double quotes
>>> str1 = 'This is a string'
>>> str1
'This is a string'
>>> greeting = "Hello World!"
>>> greeting
'Hello World!'
>>> weather = "It's a nice and warm day"
>>> weather
"It's a nice and warm day"
>>> print(weather)
It's a nice and warm day
>>> weather = 'It\'s a nice and warm day'
>>> weather
"It's a nice and warm day"
Use r prefix (stands for raw) if you do not want escape sequences to be
interpreted
12
13
#!/usr/bin/python3
"""
This line is part of multiline comment
This program shows examples of triple quoted strings
"""
# assigning multiple line string to variable
poem = """\
The woods are lovely, dark and deep,
But I have promises to keep,
And miles to go before I sleep,
And miles to go before I sleep.
"""
print(poem, end='')
Further Reading
Python docs - strings
Python docs - List of Escape Sequences and more info on strings
Python docs - Binary Sequence Types
formatting triple quoted strings
Constants
14
Built-in Operators
arithmetic operators
+ addition
- subtraction
* multiplication
/ division (float output)
// division (integer output, result is not rounded)
** exponentiation
% modulo
string operators
+ string concatenation
* string repetition
comparison operators
== equal to
> greater than
< less than
!= not equal to
15
boolean logic
and logical and
or logical or
not logical not
bitwise operators
& and
| or
^ exclusive or
~ invert bits
>> right shift
<< left shift
16
Functions
Functions
def
print function
range function
type function
Variable Scope
def
#!/usr/bin/python3
# ----- function without arguments ----def greeting():
print("-----------------------------")
print(" Hello World ")
print("-----------------------------")
greeting()
# ----- function with arguments ----def sum_two_numbers(num1, num2):
sum = num1 + num2
print("{} + {} = {}".format(num1, num2, sum))
sum_two_numbers(3, 4)
# ----- function with return value ----def num_square(num):
return num * num
my_num = 3
print(num_square(2))
print(num_square(my_num))
17
Functions
The def keyword is used to define functions
Functions have to be defined before use
A common syntax error is leaving out : at end of def statement
Block of code for functions, control structures, etc are distinguished by
indented code
4-space indentation is recommended
Python docs - Coding Style
The default return value is None
How variables are passed to functions in Python
$ ./functions.py
---------------------------- Hello World
----------------------------3 + 4 = 7
4
9
18
Functions
Often, functions can have a default behavior and if needed changed by
passing relevant argument
$ ./functions_default_arg_value.py
Default style
---------------------------- Hello World
----------------------------Style character *
*****************************
Hello World
*****************************
Style character =
=============================
Hello World
=============================
Further Reading
There are many more ways to call a function and other types of declarations, refer
the below links for more info
Python docs - defining functions
19
Functions
Python docs - Built-in Functions
print function
By default, print function adds newline character
This can be changed by passing our own string to the end argument
>>> print("hi")
hi
>>> print("hi", end='')
hi>>>
>>> print("hi", end=' !!\n')
hi !!
>>>
20
Functions
21
Functions
number formatting - specified using optional argument number, followed by
: and then the formatting style
>>> appx_pi = 22 / 7
>>> appx_pi
3.142857142857143
>>> print("{0:.2f}".format(appx_pi))
3.14
>>> print("{0:10.3f}".format(appx_pi))
3.143
different base
>>> num1
42
>>> print("42 in binary = {:b}".format(num1))
42 in binary = 101010
>>> print("42 in octal = {:o}".format(num1))
42 in octal = 52
>>> print("42 in hex = {:x}".format(num1))
42 in hex = 2a
>>> hex_str = "{:x}".format(num1)
>>> hex_str
'2a'
>>> int(hex_str, 16)
42
range function
By default start=0 and step=1 , so they can be skipped or defined as
appropriate
range(stop)
range(start, stop)
22
Functions
Note that range output doesn't include stop value - it is always upto
stop value but not including it
We'll see more about list function and data type in later chapters
>>> range(5)
range(0, 5)
>>> list(range(5))
[0, 1, 2, 3, 4]
>>> list(range(-2, 2))
[-2, -1, 0, 1]
>>> list(range(1, 15, 2))
[1, 3, 5, 7, 9, 11, 13]
>>> list(range(10, -5, -2))
[10, 8, 6, 4, 2, 0, -2, -4]
type function
Useful to check data type of a variable or value
23
Functions
>>> type(5)
<class 'int'>
>>> type('Hi there!')
<class 'str'>
>>> type(range(7))
<class 'range'>
>>> type(None)
<class 'NoneType'>
>>> type(True)
<class 'bool'>
>>> arr = list(range(4))
>>> arr
[0, 1, 2, 3]
>>> type(arr)
<class 'list'>
Variable Scope
#!/usr/bin/python3
def print_num():
print("Yeehaw! num is visible in this scope, its value is: "
+ str(num))
num = 25
print_num()
Variables defined before function call are visible within the function scope too
Python docs - Default Argument Values - see description for when default
values are evaluated
24
Functions
$ ./variable_scope_1.py
Yeehaw! num is visible in this scope, its value is: 25
What happens when a variable declared within a block is used outside of it?
#!/usr/bin/python3
def square_of_num(num):
sqr_num = num * num
square_of_num(5)
print("5 * 5 = {}".format(sqr_num))
25
Functions
$ ./variable_scope_3.py
5 * 5 = 25
If a variable name is same outside and within function definition, the one inside
the function will stay local to the block and not affect the one outside of it
#!/usr/bin/python3
sqr_num = 4
def square_of_num(num):
sqr_num = num * num
print("5 * 5 = {}".format(sqr_num))
square_of_num(5)
print("Whoops! sqr_num is still {}!".format(sqr_num))
Note that using global sqr_num will affect the sqr_num variable outside
the function
$ ./variable_scope_4.py
5 * 5 = 25
Whoops! sqr_num is still 4!
Further Reading
Python docs - scope example
Python docs - global statement
26
Integer input
#!/usr/bin/python3
usr_ip = input("Enter an integer number: ")
# Need to explicitly convert input string to desired type
usr_num = int(usr_ip)
sqr_num = usr_num * usr_num
print("Square of entered number is: {}".format(sqr_num))
27
String input
28
#!/usr/bin/python3
usr_name = input("Hi there! What's your name? ")
usr_color = input("And your favorite color is? ")
print("{}, I like the {} color too".format(usr_name, usr_color))
No need any type conversion for string and no newline character to be taken
care unlike Perl
$ ./user_input_str.py
Hi there! What's your name? learnbyexample
And your favorite color is? blue
learnbyexample, I like the blue color too
29
30
$ ./calling_shell_commands.py
Tue Jun 21 18:35:33 IST 2016
Today is Tuesday
Searching for 'hello world'
print("Hello World")
Further Reading
Python docs - subprocess
Python docs - os.system
difference between os.system and subprocess.call
Python docs - import statement
31
32
33
#!/usr/bin/python3
import subprocess
# Output includes any error messages also
print("Getting output of 'pwd' command", flush=True)
curr_working_dir = subprocess.getoutput('pwd')
print(curr_working_dir)
# Get status and output of command executed
# Exit status other than '0' is considered as something gone wro
ng
ls_command = 'ls hello_world.py xyz.py'
print("\nCalling command '{}'".format(ls_command), flush=True)
(ls_status, ls_output) = subprocess.getstatusoutput(ls_command)
print("status: {}\noutput: '{}'".format(ls_status, ls_output))
# Suppress error messages if preferred
# subprocess.call() returns status of command which can be used
instead
print("\nCalling command with error msg suppressed", flush=True)
ls_status = subprocess.call(ls_command, shell=True, stderr=subpr
ocess.DEVNULL)
print("status: {}".format(ls_status))
34
$ ./shell_command_output_redirections.py
Getting output of 'pwd' command
/home/learnbyexample/Python/python_programs
Calling command 'ls hello_world.py xyz.py'
status: 2
output: 'ls: cannot access xyz.py: No such file or directory
hello_world.py'
Calling command with error msg suppressed
hello_world.py
status: 2
35
Control Structures
Control Structures
Condition checking
if
for
while
continue and break
Condition checking
simple and combination of tests
>>> num = 5
>>> num > 2
True
>>> num > 3 and num <= 5
True
>>> 3 < num <= 5
True
>>> num % 3 == 0 or num % 5 == 0
True
>>> fav_fiction = 'Harry Potter'
>>> fav_detective = 'Sherlock Holmes'
>>> fav_fiction == fav_detective
False
>>> fav_fiction == "Harry Potter"
True
36
Control Structures
>>> bool(num)
True
>>> bool(fav_detective)
True
>>> bool(3)
True
>>> bool(0)
False
>>> bool("")
False
>>> bool(None)
False
>>> if -1:
... print("-1 evaluates to True in condition checking")
...
-1 evaluates to True in condition checking
vs this one
37
Control Structures
if
38
Control Structures
#!/usr/bin/python3
num = 45
# only if
if num > 25:
print("Hurray! {} is greater than 25".format(num))
# if-else
if num % 2 == 0:
print("{} is an even number".format(num))
else:
print("{} is an odd number".format(num))
# if-elif-else
# any number of elif can be used
if num < 0:
print("{} is a negative number".format(num))
elif num > 0:
print("{} is a positive number".format(num))
else:
print("{} is neither postive nor a negative number".format(n
um))
39
Control Structures
if-else as conditional operator
#!/usr/bin/python3
num = 42
num_type = 'even' if num % 2 == 0 else 'odd'
print("{} is an {} number".format(num, num_type))
for
#!/usr/bin/python3
number = 9
for i in range(1, 5):
mul_table = number * i
print("{} * {} = {}".format(number, i, mul_table))
40
Control Structures
$ ./for_loop.py
9 * 1 = 9
9 * 2 = 18
9 * 3 = 27
9 * 4 = 36
while
#!/usr/bin/python3
# continuously ask user input till it is a positive integer
usr_string = 'not a number'
while not usr_string.isnumeric():
usr_string = input("Enter a positive integer: ")
41
Control Structures
#!/usr/bin/python3
prev_num = 0
curr_num = 0
print("The first ten numbers in fibonacci sequence: ", end='')
for num in range(10):
print(curr_num, end=' ')
if num == 0:
curr_num = 1
continue
temp = curr_num
curr_num = curr_num + prev_num
prev_num = temp
print("")
break - skip rest of statements in the loop (if any) and exit loop
42
Control Structures
#!/usr/bin/python3
import random
while True:
# as with range() function, 500 is not inclusive
random_int = random.randrange(500)
if random_int % 4 == 0 and random_int % 6 == 0:
break
print("Random number divisible by 4 and 6: {}".format(random_int
))
in case of nested loops, continue and break only affect the immediate
parent loop
Python docs - else clauses on loops
43
Lists
Lists
Assigning List variables
Slicing and Modifying Lists
Copying Lists
List Methods and Miscellaneous
Looping
List Comprehension
Getting List as user input
44
Lists
45
Lists
The indexing format can be used to extract from list variable or modify itself
46
Lists
>>> prime[::1]
[2, 3, 5, 7, 11]
>>> prime[::2]
[2, 5, 11]
>>> prime[3:1:-1]
[7, 5]
>>> prime[::-1]
[11, 7, 5, 3, 2]
>>> prime[:]
[2, 3, 5, 7, 11]
Copying Lists
Variables in Python contain reference to objects
47
Lists
For example, when an integer variable is modified, the variable's reference is
updated with new object
the id() function returns the "identity" of an object
For variables referring to immutable types like integer and strings, this
distinction usually doesn't cause confusion in their usage
>>> a = 5
>>> id(a)
10105952
>>> a = 10
>>> id(a)
10106112
>>> b = a
>>> id(b)
10106112
>>> b = 4
>>> b
4
>>> a
10
>>> id(b)
10105920
But for variables referring to mutable types like lists, it is important to know
how variables are copied and passed to functions
When an element of list variable is modified, it does so by changing the value
(mutation) of object at that index
48
Lists
avoid copying lists using indexing format, it works for 1D lists but not for
higher dimensions
49
Lists
50
Lists
51
Lists
52
Lists
>>> prime.clear()
>>> prime
[]
>>> books = ['Harry Potter', 'Sherlock Holmes', 'To Kill a Mocki
ng Bird']
>>> del books[1]
>>> books
['Harry Potter', 'To Kill a Mocking Bird']
>>> list_2D = [[1, 3, 2, 10], [1.2, -0.2, 0, 2]]
>>> del list_2D[0][1]
>>> list_2D
[[1, 2, 10], [1.2, -0.2, 0, 2]]
>>> del list_2D[0]
>>> list_2D
[[1.2, -0.2, 0, 2]]
53
Lists
sorting
>>> a = [1, 5.3, 321, 0, 1, 2]
>>> a.sort()
>>> a
[0, 1, 1, 2, 5.3, 321]
>>> a = [1, 5.3, 321, 0, 1, 2]
>>> a.sort(reverse=True)
>>> a
[321, 5.3, 2, 1, 1, 0]
54
Lists
min and max
size of lists
>>> prime
[2, 3, 5, 7, 11]
>>> len(prime)
5
55
Lists
>>> a
[321, 5.3, 2, 1, 1, 0]
>>> sum(a)
330.3
comparing lists
>>> prime
[2, 3, 5, 7, 11]
>>> a = [4, 2]
>>> prime == a
False
>>> prime == [2, 3, 5, 11, 7]
False
>>> prime == [2, 3, 5, 7, 11]
True
56
Lists
#!/usr/bin/python3
import random
north = ['aloo tikki', 'baati', 'khichdi', 'makki roti', 'poha']
south = ['appam', 'bisibele bath', 'dosa', 'koottu', 'sevai']
west = ['dhokla', 'khakhra', 'modak', 'shiro', 'vada pav']
east = ['hando guri', 'litti', 'momo', 'rosgulla', 'shondesh']
zones = ['North', 'South', 'West', 'East']
choose_dish = [north, south, west, east]
rand_zone = random.randrange(4)
rand_dish = random.randrange(5)
zone = zones[rand_zone]
dish = choose_dish[rand_zone][rand_dish]
print("Would you like to have '{}' speciality '{}' today?".forma
t(zone, dish))
Further Reading
Python docs - more on lists
Python docs - del
Python docs - len
Python docs - dir
57
Lists
Python docs - sort
Python docs - various techniques for sorting data
Python docs - all, any
Looping
#!/usr/bin/python3
numbers = [2, 12, 3, 25, 624, 21, 5, 9, 12]
odd_numbers = []
even_numbers = []
for num in numbers:
odd_numbers.append(num) if(num % 2) else even_numbers.append
(num)
print("numbers: {}".format(numbers))
print("odd_numbers: {}".format(odd_numbers))
print("even_numbers: {}".format(even_numbers))
usually, it is enough to deal with every element of list without needing index of
elements
$ ./list_looping.py
numbers: [2, 12, 3, 25, 624, 21, 5, 9, 12]
odd_numbers: [3, 25, 21, 5, 9]
even_numbers: [2, 12, 624, 12]
58
Lists
#!/usr/bin/python3
north_dishes = ['Aloo tikki', 'Baati', 'Khichdi', 'Makki roti',
'Poha']
print("My favorite North Indian dishes:")
for idx, item in enumerate(north_dishes):
print("{}. {}".format(idx + 1, item))
chapters
$ ./list_looping_enumeration.py
My favorite North Indian dishes:
1. Aloo tikki
2. Baati
3. Khichdi
4. Makki roti
5. Poha
List Comprehension
59
Lists
#!/usr/bin/python3
import time
numbers = list(range(1,100001))
fl_square_numbers = []
# reference time
t0 = time.perf_counter()
# ------------ for loop -----------for num in numbers:
fl_square_numbers.append(num * num)
# reference time
t1 = time.perf_counter()
# ------- list comprehension ------lc_square_numbers = [num * num for num in numbers]
# performance results
t2 = time.perf_counter()
fl_time = t1 - t0
lc_time = t2 - t1
improvement = (fl_time - lc_time) / fl_time * 100
print("Time with for loop: {:.4f}".format(fl_time))
print("Time with list comprehension: {:.4f}".format(lc_time))
print("Improvement: {:.2f}%".format(improvement
))
if fl_square_numbers == lc_square_numbers:
print("\nfl_square_numbers and lc_square_numbers are equival
ent")
else:
print("\nfl_square_numbers and lc_square_numbers are NOT equ
ivalent")
60
Lists
constructs
Usually is a more readable and time saving option than loops
In this example, not having to call append() method also saves lot of time
in case of list comprehension
Time values in this example is indicative and not to be taken as absolute
It usually varies even between two runs, let alone different machines
$ ./list_comprehension.py
Time with for loop: 0.0142
Time with list comprehension: 0.0062
Improvement: 56.36%
fl_square_numbers and lc_square_numbers are equivalent
Further Reading
For more examples, including nested loops, check these
Python docs - list comprehensions
Python List Comprehensions: Explained Visually
are list comprehensions and functional functions faster than for loops
Python docs - perf_counter
understanding perf_counter and process_time
Python docs - timeit
61
Lists
Since user input is all treated as string, need to process based on agreed
delimiter and required data type
62
Strings
The indexing we saw for lists can be applied to strings as well
As strings are immutable, they can't be modified like lists though
63
64
>>> book
'Alchemist'
>>> for char in book:
... print(char)
...
A
l
c
h
e
m
i
s
t
Other operations
65
>>> book
'Alchemist'
>>> len(book)
9
>>> book.index('A')
0
>>> book.index('t')
8
>>> 'A' in book
True
>>> 'B' in book
False
>>> 'z' not in book
True
>>> min('zealous')
'a'
>>> max('zealous')
'z'
Tuples
Tuples can be thought of as sort of lists but immutable
66
Example operations
67
Tuple is handy for multiple variable assignment and returning more than one
value in functions
We have already seen example when using enumerate for iterating
over lists
68
>>> a = 5
>>> b = 20
>>> a, b = b, a
>>> a
20
>>> b
5
>>> def min_max(arr):
... return min(arr), max(arr)
...
>>> min_max([23, 53, 1, -34, 9])
(-34, 53)
69
>>> tuple('books')
('b', 'o', 'o', 'k', 's')
>>> a = [321, 899.232, 5.3, 2, 1, -1]
>>> tuple(a)
(321, 899.232, 5.3, 2, 1, -1)
Set
Set is unordered collection of objects
Mutable data type
Typically used to maintain unique sequence, perform Set operations like
intersection, union, difference, symmetric difference, etc
70
Example operations
>>> len(nums)
6
>>> nums[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'set' object does not support indexing
>>> book
'Alchemist'
>>> set(book)
{'i', 'l', 's', 'A', 'e', 'h', 'm', 't', 'c'}
>>> set([1, 5, 3, 1, 9])
{1, 9, 3, 5}
>>> list(set([1, 5, 3, 1, 9]))
[1, 9, 3, 5]
>>> nums = {1, 2, 3, 5, 6.3, 7}
>>> nums
{1, 2, 3, 5, 6.3, 7}
>>> nums.pop()
71
Dictionary
dict types can be thought of as unordered list of key:value pairs or a
72
73
74
>>> marks
{'Ravi': 92, 'Rohit': 75, 'Rahul': 86}
>>> marks['Rajan'] = 79
>>> marks
{'Ravi': 92, 'Rohit': 75, 'Rahul': 86, 'Rajan': 79}
>>> del marks['Ravi']
>>> marks
{'Rohit': 75, 'Rahul': 86, 'Rajan': 79}
>>> len(marks)
3
>>> fav_books
{'thriller': 'The Da Vinci Code', 'fantasy': 'Harry Potter', 'de
tective': 'Sherlock Holmes'}
>>> "fantasy" in fav_books
True
>>> "satire" in fav_books
False
Further Reading
Python docs - dict
Python docs - pprint
75
Text Processing
Text Processing
String methods
Regular Expressions
Pattern matching and extraction
Search and Replace
Compiling Regular Expressions
Further Reading on Regular Expressions
String methods
translate string characters
maketrans() to get translation table
translate() to perform the string mapping based on translation table
76
Text Processing
77
Text Processing
styling
width argument specifies total output string length
>>> ' Hello World '.center(40, '*')
'************* Hello World **************'
78
Text Processing
79
Text Processing
80
Text Processing
replace characters
third argument specifies how many times replace has to be performed
81
Text Processing
Further Reading
Python docs - string methods
python string methods tutorial
Regular Expressions
Handy reference of regular expression elements
Meta characters
Description
()
[]
\^
82
Text Processing
Quantifiers
Description
{n}
{n,}
{n,m}
Character
classes
Description
[aeiou]
[^aeiou]
[a-f]
\d
\D
\w
\W
\s
\S
\b
\B
83
Text Processing
Compilation
Flags
Description
re.I
ignore case
re.M
re.S
re.V
Python docs - Compilation Flags - for more details and long names for flags
Variable
Description
\g<1>, \g<2>,
\g<3> etc
84
Text Processing
>>> import re
>>> string = "This is a sample string"
>>> bool(re.search('is', string))
True
>>> bool(re.search('this', string))
False
>>> bool(re.search('this', string, re.I))
True
>>> bool(re.search('T', string))
True
>>> bool(re.search('is a', string))
True
>>> re.findall('i', string)
['i', 'i', 'i']
85
Text Processing
>>> string
'This is a sample string'
>>> re.findall('is', string)
['is', 'is']
>>> re.findall('\bis', string)
[]
>>> re.findall(r'\bis', string)
['is']
>>> re.findall(r'\w+', string)
['This', 'is', 'a', 'sample', 'string']
>>> re.split(r'\s+', string)
['This', 'is', 'a', 'sample', 'string']
>>> re.split(r'\d+', 'Sample123string54with908numbers')
['Sample', 'string', 'with', 'numbers']
>>> re.split(r'(\d+)', 'Sample123string54with908numbers')
['Sample', '123', 'string', '54', 'with', '908', 'numbers']
backreferencing
>>> quote = "So many books, so little time"
>>> re.search(r'([a-z]{2,}).*\1', quote, re.I)
<_sre.SRE_Match object; span=(0, 17), match='So many books, so'>
>>> re.search(r'([a-z])\1', quote, re.I)
<_sre.SRE_Match object; span=(9, 11), match='oo'>
>>> re.findall(r'([a-z])\1', quote, re.I)
['o', 't']
86
Text Processing
simple substitutions
re.sub will not change value of variable passed to it, has to be explicity
assigned
>>> sentence = 'This is a sample string'
>>> re.sub('sample', 'test', sentence)
'This is a test string'
>>> sentence
'This is a sample string'
>>> sentence = re.sub('sample', 'test', sentence)
>>> sentence
'This is a test string'
>>> re.sub('/', '-', '25/06/2016')
'25-06-2016'
>>> re.sub('/', '-', '25/06/2016', count=1)
'25-06/2016'
>>> greeting = '***** Have a great day *****'
>>> re.sub('\*', '=', greeting)
'===== Have a great day ====='
backreferencing
87
Text Processing
88
Text Processing
89
Text Processing
Practice tools
online regex tester shows explanations, has reference guides and ability
to save and share regex
regexone - interative tutorial
cheatsheet - one can also learn it interactively
regexcrossword - practice by solving crosswords, read 'How to play'
section before you start
90
File handling
File handling
open function
Reading files
Writing to files
open function
syntax: open(file, mode='r', buffering=-1, encoding=None, errors=None,
newline=None, closefd=True, opener=None)
>>> import locale
>>> locale.getpreferredencoding()
'UTF-8'
Reading files
91
File handling
#!/usr/bin/python3
# open file, read line by line and print it
filename = 'hello_world.py'
f = open(filename, 'r', encoding='ascii')
print("Contents of " + filename)
print('-' * 30)
for line in f:
print(line, end='')
f.close()
# 'with' is a simpler alternative, automatically handles file cl
osing
filename = 'while_loop.py'
print("\n\nContents of " + filename)
print('-' * 30)
with open(filename, 'r', encoding='ascii') as f:
for line in f:
print(line, end='')
92
File handling
$ ./file_reading.py
Contents of hello_world.py
-----------------------------#!/usr/bin/python3
print("Hello World")
Contents of while_loop.py
-----------------------------#!/usr/bin/python3
# continuously ask user input till it is a positive integer
usr_string = 'not a number'
while not usr_string.isnumeric():
usr_string = input("Enter a positive integer: ")
93
File handling
94
File handling
Writing to files
#!/usr/bin/python3
with open('new_file.txt', 'w', encoding='ascii') as f:
f.write("This is a sample line of text\n")
f.write("Yet another line\n")
95
number
Python docs - sys module
96
$ ./sum_of_two_numbers.py 2 3
2 + 3 = 5
$ echo $?
0
$ ./sum_of_two_numbers.py 2 3 7
Error: Please provide exactly two numbers as arguments
$ echo $?
1
$ ./sum_of_two_numbers.py 2 'x'
Traceback (most recent call last):
File "./sum_of_two_numbers.py", line 9, in <module>
total = int(num1) + int(num2)
ValueError: invalid literal for int() with base 10: 'x'
$ echo $?
1
97
#!/usr/bin/python3
import sys, pathlib, subprocess
if len(sys.argv) < 2:
sys.exit("Error: Please provide atleast one filename as argu
ment")
input_files = sys.argv[1:]
files_not_found = []
for filename in input_files:
if not pathlib.Path(filename).is_file():
files_not_found.append("File '{}' not found".format(file
name))
continue
line_count = subprocess.getoutput('wc -l < ' + filename)
print("{0:40}: {1:4} lines".format(filename, line_count))
print("\n".join(files_not_found))
98
$ ./varying_command_line_args.py
Error: Please provide atleast one filename as argument
$ echo $?
1
$ #selective output presented
$ ./varying_command_line_args.py *.py
calling_shell_commands.py : 14 lines
for_loop.py : 6 lines
functions_default_arg_value.py : 16 lines
functions.py : 24 lines
hello_world.py : 3 lines
if_elif_else.py : 22 lines
if_else_oneliner.py : 6 lines
shell_command_output_redirections.py : 21 lines
...
$ ./varying_command_line_args.py hello_world.py xyz.py for_loop.
py abc.py
hello_world.py : 3 lines
for_loop.py : 6 lines
File 'xyz.py' not found
File 'abc.py' not found
use os module instead of pathlib for file checking if your Python version
is not 3.4 and higher
import os
if not os.path.isfile(filename):
sys.exit("File '{}' not found".format(filename))
99
#!/usr/bin/python3
import sys, pathlib, subprocess, re
if len(sys.argv) != 2:
sys.exit("Error: Please provide exactly one filename as argu
ment")
program_name = sys.argv[0]
filename = sys.argv[1]
if not pathlib.Path(filename).is_file():
sys.exit("File '{}' not found".format(filename))
if re.search(r'line_count.py', program_name):
lc = subprocess.getoutput('wc -l < ' + filename)
print("No. of lines in '{}' is: {}".format(filename, lc))
elif re.search(r'word_count.py', program_name):
wc = subprocess.getoutput('wc -w < ' + filename)
print("No. of words in '{}' is: {}".format(filename, wc))
else:
sys.exit("Program name '{}' not recognized".format(program_n
ame))
100
$ ./line_count.py if_elif_else.py
No. of lines in 'if_elif_else.py' is: 22
$ ln -s line_count.py word_count.py
$ ./word_count.py if_elif_else.py
No. of words in 'if_elif_else.py' is: 73
$ ln -s line_count.py abc.py
$ ./abc.py if_elif_else.py
Program name './abc.py' not recognized
$ wc -lw if_elif_else.py
22 73 if_elif_else.py
using argparse module is a simpler way to build programs that behave like
shell commands
By default it adds a help option -h (short form) and --help (long form)
101
the help argument is used to specify text to be displayed for those options
in help message
102
$ ./sort_file.py
usage: sort_file.py [-h] -f FILE [-u]
sort_file.py: error: the following arguments are required: -f/-file
$ ./sort_file.py -h
usage: sort_file.py [-h] -f FILE [-u]
optional arguments:
-h, --help show this help message and exit
-f FILE, --file FILE file to be sorted
-u sort uniquely
$ ./sort_file.py -f test_list.txt
$ cat test_list.txt
async_test
basic_test
input_test
input_test
output_test
sync_test
$ ./sort_file.py -f test_list.txt -u
$ cat test_list.txt
async_test
basic_test
input_test
output_test
sync_test
$ ./sort_file.py -f xyz.txt
sort: cannot read: xyz.txt: No such file or directory
103
#!/usr/bin/python3
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('num1', type=int, help="first number")
parser.add_argument('num2', type=int, help="second number")
args = parser.parse_args()
total = args.num1 + args.num2
print("{} + {} = {}".format(args.num1, args.num2, total))
104
105
Exception Handling
We have seen plenty of errors in previous chapters when something goes
wrong or some input was given erroneously
For example:
$ ./user_input_int.py
Enter an integer number: abc
Traceback (most recent call last):
File "./user_input_int.py", line 6, in <module>
usr_num = int(usr_ip)
ValueError: invalid literal for int() with base 10: 'abc'
In such cases, it might be preferred to inform the user on the error and give a
chance to correct it
Python provides the try-except construct to achieve this
106
#!/usr/bin/python3
while True:
try:
usr_num = int(input("Enter an integer number: "))
break
except ValueError:
print("Not an integer, try again")
print("Square of entered number is: {}".format(usr_num * usr_num
))
except can be used for particular error (in this case ValueError ) or
Further Reading
Python docs - errors and exception handling
Python docs - raising exceptions
Python docs - built-in exceptions
Python docs - pass statement
Syntax check
Python's command line options can be used for variety of purposes
Syntax checking is one of them
107
Useful to quickly catch syntax errors like missing : for if for with etc
and () for print statements
While this example might be trivial, real world program might have thousands
of lines and tougher to find typos
Python docs - cmdline
One-liners: #1, #2, #3
pdb
Invoking debugger is another use of cmdline
Use it instead of using print all over a program when something goes
wrong, plus one can use breakpoints and other features specific to debugging
programs
108
l prints code around the current statement the debugger is at, useful to
Further Reading
Python docs - pdb
109
Importing program
One can also import a program directly in Interpreter to test functions
if __name__ == "__main__": construct
110
#!/usr/bin/python3
# ----- function without arguments ----def greeting():
print("-----------------------------")
print(" Hello World ")
print("-----------------------------")
# ----- function with arguments ----def sum_two_numbers(num1, num2):
sum = num1 + num2
print("{} + {} = {}".format(num1, num2, sum))
# ----- function with return value ----def num_square(num):
return num * num
# ----- main ----def main():
greeting()
sum_two_numbers(3, 4)
my_num = 3
print(num_square(2))
print(num_square(my_num))
if __name__ == "__main__":
main()
111
Further Reading
Python docs - __main__
What does if __name__ == "__main__" do?
Python packaging guide
diveintopython3 - packaging
112
Docstrings
Docstrings
Style guide
Palindrome example
Style guide
Paraphrased from Python docs - coding style
Use 4-space indentation, and no tabs.
4 spaces are a good compromise between small indentation (allows
greater nesting depth) and large indentation (easier to read). Tabs
introduce confusion, and are best left out.
Wrap lines so that they dont exceed 79 characters.
This helps users with small displays and makes it possible to have
several code files side-by-side on larger displays.
Use blank lines to separate functions and classes, and larger blocks of code
inside functions.
When possible, put comments on a line of their own.
Use docstrings.
Use spaces around operators and after commas
Name your classes and functions consistently;
the convention is to use CamelCase for classes and
lower_case_with_underscores for functions and methods
Style guides
PEP 0008
Google - pyguide
elements of python style
The Hitchhikers Guide to Python - handbook of best practices
113
Docstrings
Palindrome example
#!/usr/bin/python3
"""
Asks for user input and tells if string is palindrome or not
Allowed characters: alphabets and punctuations .,;:'"-!?
Minimum alphabets: 3 and cannot be all same
Informs if input is invalid and asks user for input again
"""
import re
def is_palindrome(usr_ip):
"""
Checks if string is a palindrome
ValueError: if string is invalid
Returns True if palindrome, False otherwise
"""
# remove punctuations & whitespace and change to all lowerca
se
ip_str = re.sub(r'[\s.;:,\'"!?-]', r'', usr_ip).lower()
if re.search(r'[^a-zA-Z]', ip_str):
raise ValueError("Characters other than alphabets and pu
nctuations")
elif len(ip_str) < 3:
raise ValueError("Less than 3 alphabets")
else:
return ip_str == ip_str[::-1] and not re.search(r'^(.)\1
+$', ip_str)
def main():
while True:
114
Docstrings
try:
usr_ip = input("Enter a palindrome: ")
if is_palindrome(usr_ip):
print("{} is a palindrome".format(usr_ip))
else:
print("{} is NOT a palindrome".format(usr_ip))
break
except ValueError as e:
print('Error: ' + str(e))
if __name__ == "__main__":
main()
The first triple quoted strings marks the docstring for entire program
The second one inside is_palindrome() is specific for that function
$ ./palindrome.py
Enter a palindrome: as2
Error: Characters other than alphabets and punctuations
Enter a palindrome: "Dammit, I'm mad!"
"Dammit, I'm mad!" is a palindrome
$ ./palindrome.py
Enter a palindrome: a'a
Error: Less than 3 alphabets
Enter a palindrome: aaa
aaa is NOT a palindrome
115
Docstrings
116
Docstrings
>>> help(palindrome.is_palindrome)
Help on function is_palindrome in module palindrome:
is_palindrome(usr_ip)
Checks if string is a palindrome
ValueError: if string is invalid
Returns True if palindrome, False otherwise
Further Reading
docstring formats
exception message capturing
117
Further Reading
Further Reading
Standard topics not covered
Useful links on coding
Python extensions
Python extensions
Cython - optimising static compiler for both the Python programming
language and the extended Cython programming language
118
Further Reading
Jython - Python for the Java Platform
NumPy - fundamental package for scientific computing with Python
119