├── .gitignore ├── README.md ├── day2 ├── conditionals.py ├── functions.py ├── jump_statements.py ├── loops.py ├── market.py ├── multiplication_tables.py ├── operators.py ├── recap.py └── sum_of_digits.py ├── day3 ├── comprehensions.py ├── dictionaries.py ├── functions.py ├── grid_city.py ├── lists.py ├── recap.py ├── sets.py └── tuples.py ├── day5 └── todos.py ├── lecture1.md ├── lecture2.md ├── lecture3.md ├── lecture4.md ├── lecture5.md ├── lecture7.md └── todo_cli ├── README.md ├── app.py ├── commands ├── __init__.py ├── lists.py └── todos.py ├── help.txt └── lists.json /.gitignore: -------------------------------------------------------------------------------- 1 | *_live/ 2 | __pycache__ 3 | .vscode/ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction to Python 2 | 3 | Objectives: 4 | - Introduce python from the absolute basics. 5 | - Create a simple Todo application for the commandline 6 | - Introduce Django 7 | - Create a Todo application website 8 | - Deploy on heroku 9 | 10 | To discuss any doubts or questions after today's class with the community, join Scaler Club: https://chat.scaler.com/signup_user_complete/?id=c9os5g9kobr4jqmtgadgkbgafa 11 | 12 | 13 | # Lectures 14 | - Lecture 1: [[Notes]](/lecture1.md) [[Video]](https://www.youtube.com/watch?v=OrzXiZKtudA) - Installing Python, REPL, using Python as a calculator, basic data types, input and output 15 | - Lecture 2: [[Notes]](/lecture2.md) [[Video]](https://www.youtube.com/watch?v=Q7nvvSlWem4) - Operators, Basic Control Flow - Conditionals, Loops and Functions 16 | - Lecture 3: [[Notes]](/lecture3.md) [[Video]](https://www.youtube.com/watch?v=tmxCgqNSj88) - Basic Data Structures and Containers: Lists, Tuples, Sets, Dictionaries 17 | - Lecture 4: [[Notes]](/lecture4.md) [[Video]](https://www.youtube.com/watch?v=NsOzuuLlR08) - Organizing Code & Dependency Management 18 | - Lecture 5: [[Notes]](/lecture5.md) [[Video]](https://www.youtube.com/watch?v=kj61srFJ9fY) - File I/O, reading and writing text, csv and json files 19 | - Lecture 6: [[Notes]](todo_cli/README.md) [[Video]](https://www.youtube.com/watch?v=tHDoTDpfRE4) - Building a Todo CLI App with Python 20 | - Lecture 7: [[Notes]](/lecture7.md) [[Video]](https://www.youtube.com/watch?v=G4C3KYYQV8k) - Advanced Python 21 | -- -- 22 | 23 | [[Next: Introduction to Django Series - Notes and Videos]](https://github.com/scaleracademy/intro-to-django) -------------------------------------------------------------------------------- /day2/conditionals.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This program checks if a message is rude or polite 3 | A message is rude if the parameter x is less than 1 or greater than 10 4 | ''' 5 | 6 | x = int(input()) 7 | 8 | if (x < 1): 9 | print("Rude message") 10 | 11 | if (x > 10): 12 | print("Rude message") 13 | 14 | ''' 15 | The problem with the above code is redundancy! 16 | A principal rule of programming is to never ever have 17 | two pieces of code to do the same thing. 18 | It can be improved as shown below: 19 | ''' 20 | if (x < 1 or x > 10): 21 | print("Rude message") 22 | 23 | if (x >= 1 and x <= 10): 24 | print("Polite message") 25 | 26 | ''' 27 | The problem with above code is robustness 28 | what if the condition of rudeness changes and we will have to 29 | rewrite both the conditions above, 30 | we can simplify it using an else construct :) 31 | ''' 32 | 33 | if (x < 1 or x > 10): 34 | print("Rude message") 35 | else: 36 | print("Polite message") 37 | 38 | # if elif 39 | # say if only x < 1 are rude messages 40 | # from 1 to 10 are polite messages 41 | # and after 10 are other types! 42 | if (x < 1): 43 | print("Rude messsage") 44 | elif (x >= 1 and x <= 10): 45 | print("Polite message") 46 | else: 47 | print("Any other message") -------------------------------------------------------------------------------- /day2/functions.py: -------------------------------------------------------------------------------- 1 | def print_function(): 2 | print("This function just prints to the screen!") 3 | 4 | x = print_function() # Function which does not return anything, returns 'None' 5 | print(x) 6 | ''' 7 | Output: 8 | This function just prints to the screen! 9 | None 10 | ''' 11 | 12 | def sum_of_two(num_1, num_2): 13 | return num_1 + num_2 14 | 15 | res = sum_of_two(1, 100) 16 | print(res) 17 | 18 | # functions can accept arguments with default values (called as keyword arguments) 19 | def greetings(name="Scaler"): 20 | print(f"Hello from {name}") 21 | 22 | greetings() 23 | greetings("InterviewBit") 24 | 25 | # Exercise, complete the following function that returns maximum of three numbers 26 | # def max_of_three(num_1, num_2, num_3) -------------------------------------------------------------------------------- /day2/jump_statements.py: -------------------------------------------------------------------------------- 1 | # break and continue allow to control the flow of the loops 2 | 3 | # using break, we can go outside the loop 4 | names = ["Scaler", "Interviewbit", "scaler", "interviewbit"] 5 | for name in names: 6 | print(name) 7 | if (name == "Scaler"): 8 | break 9 | 10 | # using continue, we can skip a particular iteration, and go to next one 11 | for name in names: 12 | if (name == "Scaler"): 13 | continue 14 | print(name) 15 | 16 | # using break in nested loops 17 | # break in the inner loop just breaks out of the inner loop 18 | # outer loop will continue to run 19 | target = 'i' 20 | for name in names: 21 | print(f"{name} in outer loop") 22 | for char in name: 23 | if char == target: 24 | print(f"Found {name} with letter: {target}") 25 | print("Breaking out of the inner loop") 26 | break -------------------------------------------------------------------------------- /day2/loops.py: -------------------------------------------------------------------------------- 1 | # print numbers from 1 to 10 to the screen 2 | ''' 3 | print(1) 4 | print(2) 5 | ... 6 | print(10) 7 | 8 | The above is not a good practice since our requirement 9 | might change and we might have to print from 1 to n, where n is the input. 10 | Also, the code is repititive, that is why language provides loop constructs! 11 | ''' 12 | 13 | # for loops in python do not have initialization, condition, update statement like in other langs 14 | # in keyword is used along with for, to iterate over items in a container or sequence 15 | 16 | for n in range(10): 17 | print(n, end=' ') 18 | print() # by default, end = '\n' 19 | 20 | # the above code prints '0 1 2 ... 9' 21 | # we want to print '1 2 3 ... 10' 22 | 23 | for n in range(1, 11): 24 | print(n, end=' ') 25 | print() 26 | 27 | # let us say we want to print all even numbers from 1 to 10 28 | 29 | for n in range(2, 11, 2): 30 | print(n, end=' ') 31 | print() 32 | 33 | # can use list operator before range, to print the items in the range 34 | print(list(range(2, 11, 2))) 35 | 36 | # doing the same thing using a while loop 37 | counter = 0 38 | while (counter < 10): 39 | counter += 1 40 | print(counter, end=' ') 41 | print() 42 | 43 | # NOTE: while loops usually have a statement to update the sentinel value (being checked in condition) 44 | # otherwise the loop can run infinitely, use Ctrl-C to exit the infinite loop 45 | # the loop below runs infinitely 46 | 47 | ''' 48 | counter = 0 49 | while (counter < 10): 50 | print(counter, end=' ') 51 | ''' -------------------------------------------------------------------------------- /day2/market.py: -------------------------------------------------------------------------------- 1 | vegetable_market = ["onion", "tomato", "broccoli", "cabbage"] 2 | 3 | if "carret" in vegetable_market: 4 | print("Bought carret!") 5 | elif "cabbage" in vegetable_market: 6 | print("Bought cabbage!") 7 | else: 8 | print("Came back empty handed...") -------------------------------------------------------------------------------- /day2/multiplication_tables.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Program to print multiplication tables of numbers from 1 to n 3 | ''' 4 | n = int(input()) 5 | 6 | for multiple in range(1, 11): 7 | for number in range(1, n + 1): 8 | print(number*multiple, end=' ') 9 | print() 10 | 11 | # formatted output 12 | for multiple in range(1, 11): 13 | for number in range(1, n + 1): 14 | print("%4d"%(number*multiple), end=' ') 15 | print() -------------------------------------------------------------------------------- /day2/operators.py: -------------------------------------------------------------------------------- 1 | # comparison operators 2 | a = 3 3 | less_than_3 = a < 3 4 | print(less_than_3) # False 5 | print(type(less_than_3)) # 6 | 7 | # other relational operators: >, >=, ==, != 8 | print(a == 3) # True 9 | print(a != 3) # False 10 | 11 | # logical operators: or, and, not 12 | x = 5 13 | res_one = x < 1 or x > 10 14 | res_two = x >= 1 and x <= 10 15 | print(res_one) # False 16 | print(res_two) # True 17 | 18 | user_logged_in = True 19 | print(not user_logged_in) 20 | 21 | # the integer 0 is always False, and every other number, is True 22 | x = bool(0) 23 | y = bool(-1) 24 | z = bool(1) 25 | print(x, y, z) # False True True 26 | 27 | # strings are compared lexicographically, i.e. by ASCII value of the characters 28 | # you can remeber that capital letters come before lower case ones 29 | print("Scaler" > "Interviewbit") # True as 'S' comes after 'I' 30 | print('s' > 'S') # True 31 | print("Scaler" == "Interviewbit") # False 32 | 33 | # Identity comparisons, is keyword is used 34 | # if the compared objects are stored in the same memory location, returns true 35 | a = "Scaler" 36 | b = "Scaler" 37 | print(a is b) 38 | print(id(a)) 39 | print(id(b)) 40 | 41 | # bitwise operators 42 | a = 3 43 | b = 5 44 | c = a & b 45 | ''' 46 | Bitwise AND (&) 47 | In result, bit is set at those positions where it is set in both the operands 48 | 011 49 | & 101 50 | --- 51 | 001 52 | --- 53 | ''' 54 | print(c) 55 | 56 | # Exercise 57 | a = False 58 | b = True 59 | c = True 60 | 61 | print (a or b and c) 62 | 63 | # Read about operator precedences -------------------------------------------------------------------------------- /day2/recap.py: -------------------------------------------------------------------------------- 1 | # Quick Recap 2 | 3 | # variables 4 | lecture_day = 2 5 | print(lecture_day) 6 | 7 | # numbers can be int, float or complex 8 | square_area = 36 9 | circle_area = 6.28 10 | iota = (-1) ** (1/2) 11 | print(square_area, circle_area, iota) 12 | 13 | # basic mathematical operators 14 | print(square_area + circle_area) 15 | print(4 * square_area) 16 | print(iota/square_area) 17 | 18 | # type function 19 | print(type(iota)) 20 | 21 | # strings 22 | greeting = "Hello from Scaler!" 23 | print(greeting) 24 | 25 | # f-strings 26 | msg = "Hello from" 27 | name = "Scaler" 28 | print(f"{msg} {name}!") 29 | 30 | # input from user 31 | num1 = int(input()) 32 | num2 = int(input()) 33 | print(num1 + num2) 34 | 35 | # none value 36 | x = None 37 | print(x) -------------------------------------------------------------------------------- /day2/sum_of_digits.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Program to find sum of digits of a number 3 | ''' 4 | n = int(input()) 5 | 6 | # say n = 1234, how do you compute the sum of the digits? 7 | # you see all the digits, 1, 2, 3, 4, and add them up in a go, boom => 10 is the answer 8 | 9 | # How do we program the computer to do this for us? 10 | # We should follow the same technique, right? 11 | # Loop through all the digits, and add them up one by one! 12 | # So, our computer will store the result at some place, we need to create a variable 13 | # Say sum = 0 14 | # How to find a particular digit? 15 | # n = 1234, can we say last digit is the one we get after finding remainder when n is divided by 10 16 | # i.e. n % 10 = 4, add this 4 to the sum, now sum = 4 17 | # Now, we can divide n by 10, to get n' = 1234//10 = 123 (integer division!) 18 | # We continue this process, until n becomes zero!!! 19 | # Pseudocode: 20 | ''' 21 | n = input from user 22 | sum = 0 23 | while (n > 0) 24 | d = last digit of n (i.e. n % 10) 25 | add d to sum 26 | divide n by 10 27 | print(sum) 28 | ''' 29 | 30 | sum = 0 31 | while (n > 0): 32 | d = n % 10 33 | sum += d # shorthand for sum = sum + d 34 | n //= 10 # shorthand for n = n//10 35 | print(sum) 36 | 37 | # Try yourself: 38 | # 1. Count digits in a number 39 | # 2. Reverse a number 40 | # 3. Find all factors of a number -------------------------------------------------------------------------------- /day3/comprehensions.py: -------------------------------------------------------------------------------- 1 | # given a list of strings, find lengths of each of them 2 | names = ["scaler", "interviewbit"] 3 | len_list = [] 4 | for name in names: 5 | len_list.append(len(name)) 6 | print(len_list) 7 | 8 | # using list comprehension 9 | len_list = [len(name) for name in names] 10 | len_list = [("length", len(name)) for name in names] 11 | print(len_list) 12 | # with odd lengths 13 | len_list = [("length", len(name)) for name in names if len(name) % 2 == 1] 14 | print(len_list) 15 | 16 | # sum of all even numbers from 1 to 100 17 | sum_even = sum([num for num in range(1, 101) if num % 2 == 0]) 18 | print(sum_even) -------------------------------------------------------------------------------- /day3/dictionaries.py: -------------------------------------------------------------------------------- 1 | # dict allows us to store data in (key, value) pairs 2 | # themselves are mutable but can contain only immutable types as keys, like sets 3 | # very useful for accessing data based on a key, quickly 4 | 5 | # creating empty dict 6 | day_mapping = {} 7 | day_mapping = dict() 8 | 9 | # dict with items (key, value) pairs 10 | day_mapping = { 11 | "Monday": 1, 12 | "Tuesday": 2, 13 | "Wednesday": 3, 14 | "Thursday": 4, 15 | "Friday": 5, 16 | "Saturday": 6, 17 | "Sunday": 0 18 | } 19 | print(len(day_mapping)) # 7 20 | 21 | # items can be accessed based on the key, not the index 22 | print(day_mapping["Wednesday"]) # 3 23 | print(day_mapping.get("Sunday")) 24 | print(day_mapping.get("sunday")) # None, because the key is not present 25 | 26 | # updating value for a particular key 27 | day_mapping["Sunday"] = 7 28 | # adding another key 29 | day_mapping["Default"] = 0 30 | 31 | # keys, values and items 32 | print(day_mapping.keys()) 33 | print(day_mapping.values()) 34 | print(day_mapping.items()) 35 | 36 | # removing a particular key 37 | del(day_mapping["Default"]) 38 | print(day_mapping.keys()) -------------------------------------------------------------------------------- /day3/functions.py: -------------------------------------------------------------------------------- 1 | # arguments can be of two types: with default values and without default values 2 | # those with default values are called keyword arguments 3 | # for eg the print function we use has 'sep' as a keyword argument which is '\n' by default 4 | 5 | # below is also a way you can document your function using docstrings 6 | def distance_travelled(t, u = 0, g = 9.81): 7 | """ 8 | Function distance_travelled calculates the distance travelled by an object 9 | with initial speed u, in a time interval of t, where acceleration due to gravity is g 10 | 11 | input: t (time taken), u (initial speed) g (acceleration due to gravity) 12 | output: distance travelled 13 | 14 | Example: 15 | >>> distance_travelled(1.0) 16 | 17 | 4.905 18 | """ 19 | d = u*t + 0.5 * g * t**2 20 | return d 21 | 22 | print(distance_travelled(2.0)) 23 | print(distance_travelled(2.0, u = 1.0)) 24 | print(distance_travelled(2.0, g = 9.7)) 25 | print(distance_travelled(g = 9.7, t = 2.0)) 26 | 27 | # scope inside a function is different than the one outside it 28 | # inside function scope, you can access the outer scope variables but cannot change them 29 | 30 | def set_name(input_name): 31 | name = input_name 32 | print(f"Name inside the function: {name}") 33 | 34 | set_name("Scaler") 35 | # print(name) # NameError: this variable is not defined 36 | 37 | """ 38 | # Exercise: What should be the output for this piece of code? 39 | def add_char_to_list(char, lst = []): 40 | lst.append(char) 41 | return lst 42 | add_char_to_list('s') 43 | add_char_to_list('c') 44 | add_char_to_list('a') 45 | add_char_to_list('l') 46 | add_char_to_list('e') 47 | print(''.join(add_char_to_list('r'))) 48 | """ -------------------------------------------------------------------------------- /day3/grid_city.py: -------------------------------------------------------------------------------- 1 | # take a m * n grid (matrix) as input 2 | # print the sum of all the elements, max, 3 | # and the sum of left_diagonal 4 | 5 | n, m = map(int, input().split()) 6 | 7 | matrix = [] 8 | for r in range(n): 9 | row = list(map(int, input().split())) 10 | matrix.append(row) 11 | 12 | print(matrix) 13 | -------------------------------------------------------------------------------- /day3/lists.py: -------------------------------------------------------------------------------- 1 | # lists: container objects used to store related items together 2 | # let us say you were to input n numbers from user and find their sum, average, etc. 3 | # also you need the ability to sort the numbers etc 4 | # so you need some data type to store them easily, take input and print some required data 5 | 6 | number_list = [] 7 | number_list = [10, 4, 1, 5] 8 | print(type(number_list)) 9 | 10 | # 0-based indexing to access elements in the list 11 | # order is retained in the list! 12 | first_num = number_list[0] 13 | last_num = number_list[-1] 14 | print(f"First: {first_num}, Last: {last_num}") 15 | 16 | # common methods on lists 17 | print(f"Number list: {number_list}") 18 | 19 | num_count = len(number_list) 20 | print(f"Count: {num_count}") 21 | 22 | number_list.append(7) 23 | print(f"Appended 7: {number_list}") 24 | 25 | number_list.insert(1, 6) 26 | print(f"Insert 6 at index 1: {number_list}") 27 | 28 | number_list.pop() 29 | print(f"Removed the last element: {number_list}") 30 | 31 | # lists are mutable, can change the elements in-place 32 | # sorting lists, sorted method returns a new list 33 | ordered_num_list = sorted(number_list) 34 | print(f"Ordered number list: {ordered_num_list}") 35 | print(f"Original number list: {number_list}") 36 | 37 | # sorting in place, descending order 38 | number_list.sort(reverse=True) 39 | print(f"Original number list: {number_list}") 40 | # reversing a list in-place 41 | number_list.reverse() 42 | print(f"Reversed number list: {number_list}") 43 | 44 | # extending one list into another 45 | l1 = [1, 2, 3, 4] 46 | l2 = [5, 6, 7, 10] 47 | l1.extend(l2) 48 | print(l1) 49 | print(l2) 50 | 51 | # checking if an item is present in a list (in keyword) 52 | print(5 in l1) 53 | print(8 in l2) 54 | 55 | # split and join 56 | input_str = "1 2 3 4 5 6" 57 | input_list = input_str.split() 58 | print(input_list) 59 | 60 | print(','.join(input_list)) -------------------------------------------------------------------------------- /day3/recap.py: -------------------------------------------------------------------------------- 1 | """ 2 | program to check if the number (say 'n') given as input is a prime 3 | a prime no. is the one which has only 1 and the numbers itself as its divisors 4 | 1 is not a prime no. 5 | eg. n = 2, 3, 5, 7, ... 6 | 7 | idea: start a loop from 2 to n/2, if n is divisble by the divisor => not prime 8 | because a no. cannot be divided by a no. > n/2 except n 9 | """ 10 | 11 | n = int(input()) 12 | checked = 0 13 | for divisor in range(2, n//2 + 1): 14 | if (n % divisor == 0): 15 | print("No is not prime!") 16 | checked = 1 17 | # no need checking further, can break the loop here itself 18 | break 19 | 20 | # the above code doesn't say that 1 is not a prime because loop won't run even once 21 | # to handle that case, we can add the extra condition: 22 | if (n == 1): 23 | print("No is not prime!") 24 | checked = 1 25 | 26 | # in cases where checked is false or equal to 0, can say it is prime! 27 | if (not checked): 28 | print("No is prime!") 29 | 30 | 31 | """ 32 | program to print the following pattern: 33 | 34 | * 35 | * * 36 | * * * 37 | * * * * 38 | ... 39 | 40 | idea: As you can observer, we are looping in two directions, row wise and column wise 41 | 1st row has 1 star 42 | 2nd row has 2 stars 43 | 3rd row has 3 stars and so on... 44 | 45 | the outer loop would represent looping over the rows 46 | and in the inner loop, we will loop over the elements in the rows, i.e. columns 47 | 48 | Always better to use loop variable 'r' or 'row' for looping on rows 49 | and the loop variable 'c' or 'col' to loop on columns 50 | for easy understanding and debugging of your code ! 51 | """ 52 | 53 | num_rows = n 54 | for row in range(1, num_rows + 1): 55 | # r_th row will have r stars 56 | for col in range(1, row + 1): 57 | print('*', end=' ') 58 | # endline 59 | print('') 60 | 61 | # is it possible to do the same thing using one loop, think? 62 | 63 | # idea is the same: print 1 char in 1st row, 2 chars in 2nd row, ... 64 | line_num = 1 65 | printed_on_cur_row = 0 66 | while (line_num <= num_rows): 67 | if (printed_on_cur_row < line_num): 68 | print('*', end=' ') 69 | printed_on_cur_row += 1 70 | else: 71 | print('') 72 | # reset count of stars on cur_row to be zero 73 | printed_on_cur_row = 0 74 | # increment the line_num, i.e. move to next row 75 | line_num += 1 76 | 77 | """ 78 | function to return maximum of three numbers 79 | 80 | idea: let numbers be a, b, c 81 | when can a be the max? when a >= b and a >= c 82 | similarly for b and c 83 | so, write three conditions, and return the answer if that condition is true 84 | also, you can use if elif else as well! 85 | """ 86 | 87 | def maximum_of_three(num_one, num_two, num_three): 88 | if (num_one >= num_two and num_one >= num_three): 89 | return num_one 90 | if (num_two >= num_one and num_two >= num_three): 91 | return num_two 92 | if (num_three >= num_one and num_three >= num_two): 93 | return num_three 94 | return -1 95 | 96 | n1 = 3 97 | n2 = 7 98 | n3 = 1 99 | 100 | res = maximum_of_three(n1, n2, n3) 101 | print(res) 102 | 103 | # idea: assign max = a, now check if b >= max, max = b, again if c >= max, max = c 104 | def maximum_of_three_simple(n1, n2, n3): 105 | maxi = n1 106 | if (n2 >= maxi): 107 | maxi = n2 108 | if (n3 >= maxi): 109 | maxi = n3 110 | return maxi 111 | 112 | res = maximum_of_three(n1, n2, n3) 113 | print(res) -------------------------------------------------------------------------------- /day3/sets.py: -------------------------------------------------------------------------------- 1 | # sets help to store data in an unsorted way 2 | # an item can only be present once in a set, i.e. no duplicates 3 | # membership test is very fast 4 | # other powerful operations provided are: union, difference and intersection 5 | 6 | prime_set = set() 7 | prime_set.add(1) 8 | prime_set.add(2) 9 | prime_set.add(3) 10 | prime_set.add(11) 11 | # order is not preserved in a set 12 | print(f"Prime set: {prime_set}") 13 | 14 | # remove an item from a set 15 | prime_set.discard(1) 16 | print(f"Prime set: {prime_set}") 17 | 18 | # x = prime_set[0] # cannot access set items using an index 19 | # prime_set.sort() # cannot sort items in a set 20 | # sorted method can still be used as that will convert set to a list 21 | 22 | # single element set 23 | s = {1} 24 | print(s) 25 | print(type(s)) 26 | 27 | s = {} 28 | print(type(s)) # 29 | # to create empty set, rather use set constructor 30 | s = set() 31 | print(type(s)) # 32 | 33 | prime_set = {2, 3, 5, 5, 3, 7} 34 | print(prime_set) # duplicate values not present 35 | 36 | # sets internally use hashing to store the elements and check if it is present or not 37 | # a numerical value is associated with any item in the set, try using hash() method 38 | # hash() function works only on immutable data types, so you cannot create a set of mutable types 39 | 40 | names = {"scaler", "interviewbit", "scaler"} 41 | print(names) 42 | # both the following hash values will come out to be same! although values can change 43 | # depending on when the program is run 44 | print(hash("scaler")) 45 | print(hash("scaler")) 46 | 47 | # set_of_lists = {[1, 2, 3], [1, 2, 3, 4]} # TypeError: unhashable type: 'list' 48 | 49 | # we can convert a list into a set using the set constructor 50 | names = ["scaler", "interviewbit", "scaler"] 51 | names_set = set(names) 52 | print(names_set) 53 | 54 | # update is used to update set with another sequence 55 | prime_set.update(names_set) 56 | print(prime_set) 57 | prime_set.update("scaler") 58 | # since string is a sequence, each of its characters will get added to the set! 59 | print(prime_set) 60 | 61 | # union (|), intesection (&), difference (^) -------------------------------------------------------------------------------- /day3/tuples.py: -------------------------------------------------------------------------------- 1 | # tuples are used to keep track of related but different items 2 | # they are immutable, you cannot change the items in it once created! 3 | # a use-case could be to store a row in a spreadsheet, given that 4 | # we need read-only snapshot of data 5 | 6 | point = () 7 | # point = collection of x, y and z coordinates! 8 | point = (3, 4, 5) 9 | print(point) 10 | print(type(point)) 11 | 12 | # checking for existence of an item 13 | print(3 in point) 14 | print(6 in point) 15 | 16 | # access item using index as well 17 | print(f"x = {point[0]}, y = {point[1]}, z = {point[2]}") 18 | 19 | # point[0] = 10 # TypeError: 'tuple' object does not support this assignment 20 | 21 | # to create single item tuple, we need to give a comma after the item 22 | single_element = (1) 23 | print(type(single_element)) # 24 | 25 | single_element = (1, ) 26 | print(single_element) 27 | print(type(single_element)) # 28 | 29 | # unpacking tuple data 30 | x, y, z = point 31 | print(x, y, z) 32 | 33 | # functions can as well return multiple values with the help of tuples -------------------------------------------------------------------------------- /day5/todos.py: -------------------------------------------------------------------------------- 1 | """ 2 | The program fetches a json file and deserializes it 3 | """ 4 | 5 | import json 6 | import requests 7 | 8 | URL = "https://jsonplaceholder.typicode.com/todos" 9 | response = requests.get(URL) 10 | todos = json.loads(response.text) 11 | 12 | print(todos[0]) -------------------------------------------------------------------------------- /lecture1.md: -------------------------------------------------------------------------------- 1 | 2 | Installation 3 | ------------ 4 | 5 | - download from https://www.python.org/ 6 | - instructions https://realpython.com/installing-python/ 7 | - linux: 8 | ```bash 9 | sudo apt-get update 10 | sudo apt-get install python3.8 python3-pip 11 | sudo apt-get install python3-virtualenv 12 | ``` 13 | - for now, use repl.it 14 | 15 | Python 16 | --------- 17 | 18 | - Programming language 19 | - General purpose 20 | - Very high level 21 | - Simple, easy to learn, but powerful 22 | - Dynamically typed, but strongly typed (has static type checkers) 23 | - Multi paradigm - supports OOP, functional, procedural, Async 24 | - Excellent tooling - Pycharm, extensions for all major editors, flake8, pylint, black, mypy 25 | - Mature and extensive ecosystem 26 | - Seen mostly in 27 | - Web Development - django, flask 28 | - Data Analytics and Machine Learning - numpy, scipy, matplotlib, sklearn, ternsorflow, torch, pandas 29 | - DevOps & Scripting 30 | - Distributed Computing - pyspark, dask 31 | - Awesome-Python: [https://github.com/vinta/awesome-python](https://github.com/vinta/awesome-python) 32 | 33 | # Basics 34 | ```py 35 | 2 + 2 * 2 - 2 / 2 // 2 ** 2 36 | 10 / 3 37 | 10 // 3 38 | 5 ** 5 39 | (-1) ** (1/2) 40 | ``` 41 | 42 | ```py 43 | width = 20 44 | height = 50 45 | area = width * height 46 | _ 47 | x 48 | ``` 49 | 50 | ```py 51 | 'hello, world' 52 | # escaping special chars, triple quoted, double quoted, f-strings, byte-strings 53 | # comments 54 | ``` 55 | 56 | ```py 57 | print('Hello, World!') 58 | x = int(input('Enter number')) 59 | ``` 60 | 61 | 62 | ```py 63 | x = int(input('Enter number')) 64 | y = int(input('Enter number')) 65 | operator = input('Enter operator') 66 | operator = operator.strip().lower() 67 | if operator == 'add': 68 | print(f'{x} + {y} = {x+y}') 69 | elif operator == 'power': 70 | print(f'{x} ^ {y} = {x ** y}') 71 | else: 72 | print('I don\'t know what to do') 73 | ``` 74 | 75 | ```py 76 | classes = ['ds-algo', 'python', 'machine-learning', 'ama'] 77 | for c in classes: 78 | print(c, len(c), c.upper(), c.lower()) 79 | 80 | # can't use class as a variable name, because it is a keyword 81 | import keyword 82 | keyword.kwlist 83 | ``` 84 | 85 | ```py 86 | for i in range(10): 87 | print(f'Square of {i} is {i**2}') 88 | ``` 89 | 90 | ```py 91 | range(10) 92 | range(1, 10) 93 | range(1, 10, -1) 94 | ``` 95 | 96 | ```py 97 | classes = ['ds-algo', 'python', 'machine-learning', 'ama'] 98 | for index, c in enumerate(classes): 99 | print(index, c, len(c), c.upper(), c.lower()) 100 | ``` 101 | 102 | ```py 103 | sum(range(1000)) 104 | list(range(1000)) 105 | ``` 106 | 107 | ```py 108 | while True: 109 | pass 110 | 111 | i = 0 112 | while i < 10: 113 | print(i) 114 | i += 1 115 | ``` 116 | 117 | ```py 118 | def foo(): 119 | pass 120 | 121 | def fib(n): 122 | if n <= 1: return n 123 | return fib(n-1) + fib(n-2) 124 | 125 | from functools import lru_cache 126 | 127 | help() 128 | dir() 129 | a, b = b, a 130 | snake_case 131 | collections.Counter 132 | import math 133 | math.pi 134 | math.e 135 | ``` 136 | 137 | -------------------------------------------------------------------------------- /lecture2.md: -------------------------------------------------------------------------------- 1 | # Day 2: Flow Control 2 | 3 | ## Day 1 Recap 4 | [Basics of Python: Code](day2/recap.py) 5 | 6 | ```py 7 | # variables 8 | lecture_day = 2 9 | print(lecture_day) 10 | ``` 11 | 12 | ```py 13 | # numbers can be int, float or complex 14 | square_area = 36 15 | circle_area = 6.28 16 | iota = (-1) ** (1/2) 17 | print(square_area, circle_area, iota) 18 | ``` 19 | 20 | ```py 21 | # basic mathematical operators 22 | print(square_area + circle_area) 23 | print(4 * square_area) 24 | print(iota/square_area) 25 | 26 | # type function 27 | print(type(iota)) 28 | ``` 29 | 30 | ```py 31 | # strings 32 | greeting = "Hello from Scaler!" 33 | print(greeting) 34 | 35 | # f-strings 36 | msg = "Hello from" 37 | name = "Scaler" 38 | print(f"{msg} {name}!") 39 | ``` 40 | 41 | ```py 42 | # input from user 43 | num1 = int(input()) 44 | num2 = int(input()) 45 | print(num1 + num2) 46 | ``` 47 | 48 | ```py 49 | # none value 50 | x = None 51 | print(x) 52 | ``` 53 | 54 | ## Operators 55 | [Code](day2/operators.py) 56 | 57 | ### Relational Operators 58 | - comparison operators (<, >, <=, >=) 59 | - Equals (==) 60 | - Not equals (!=) 61 | 62 | ### Logical Operators 63 | - and 64 | - or 65 | - not 66 | 67 | ```py 68 | # comparison operators 69 | a = 3 70 | less_than_3 = a < 3 71 | print(less_than_3) # False 72 | print(type(less_than_3)) # 73 | ``` 74 | 75 | ```py 76 | # other relational operators: >, >=, ==, != 77 | print(a == 3) # True 78 | print(a != 3) # False 79 | ``` 80 | 81 | ```py 82 | # logical operators: or, and, not 83 | x = 5 84 | res_one = x < 1 or x > 10 85 | res_two = x >= 1 and x <= 10 86 | print(res_one) # False 87 | print(res_two) # True 88 | 89 | user_logged_in = True 90 | print(not user_logged_in) 91 | ``` 92 | 93 | ```py 94 | # the integer 0 is always False, and every other number, is True 95 | x = bool(0) 96 | y = bool(-1) 97 | z = bool(1) 98 | print(x, y, z) # False True True 99 | ``` 100 | 101 | ```py 102 | # strings are compared lexicographically, i.e. by ASCII value of the characters 103 | # you can remeber that capital letters come before lower case ones 104 | print("Scaler" > "Interviewbit") # True as 'S' comes after 'I' 105 | print('s' > 'S') # True 106 | print("Scaler" == "Interviewbit") # False 107 | ``` 108 | 109 | ```py 110 | # Identity comparisons, is keyword is used 111 | # if the compared objects are stored in the same memory location, returns true 112 | a = "Scaler" 113 | b = "Scaler" 114 | print(a is b) 115 | print(id(a)) 116 | print(id(b)) 117 | ``` 118 | 119 | ```py 120 | # bitwise operators 121 | a = 3 122 | b = 5 123 | c = a & b 124 | ''' 125 | Bitwise AND (&) 126 | In result, bit is set at those positions where it is set in both the operands 127 | 011 128 | & 101 129 | --- 130 | 001 131 | --- 132 | ''' 133 | print(c) 134 | ``` 135 | 136 | ```py 137 | # Exercise 138 | a = False 139 | b = True 140 | c = True 141 | 142 | print (a or b and c) 143 | 144 | # Read about operator precedences 145 | ``` 146 | 147 | ## Conditionals 148 | 149 | ### Codes 150 | - [Basic constructs](day2/conditionals.py) 151 | - [Market example for if elif else](day2/market.py) 152 | 153 | ### Decision making and constructs 154 | 155 | - Decision making statements in programming languages decide the direction of flow of program execution. 156 | 157 | - There comes situations in real life when we need to make some decisions and based on these decisions, we decide what should we do next. 158 | 159 | - Similar situations arise in programming also where we need to make some decisions and based on these decision we will execute the next block of code. 160 | 161 | - Majorly, the following 3 conditional constructs are used in Python: 162 | - if 163 | - else 164 | - elif 165 | 166 | ```py 167 | ''' 168 | This program checks if a message is rude or polite 169 | A message is rude if the parameter x is less than 1 or greater than 10 170 | ''' 171 | 172 | x = int(input()) 173 | 174 | if (x < 1): 175 | print("Rude message") 176 | 177 | if (x > 10): 178 | print("Rude message") 179 | ``` 180 | 181 | ```py 182 | ''' 183 | The problem with the above code is redundancy! 184 | A principal rule of programming is to never ever have 185 | two pieces of code to do the same thing. 186 | It can be improved as shown below: 187 | ''' 188 | if (x < 1 or x > 10): 189 | print("Rude message") 190 | 191 | if (x >= 1 and x <= 10): 192 | print("Polite message") 193 | ``` 194 | 195 | ```py 196 | ''' 197 | The problem with above code is robustness 198 | what if the condition of rudeness changes and we will have to 199 | rewrite both the conditions above, 200 | we can simplify it using an else construct :) 201 | ''' 202 | 203 | if (x < 1 or x > 10): 204 | print("Rude message") 205 | else: 206 | print("Polite message") 207 | ``` 208 | 209 | ```py 210 | # if elif 211 | # say if only x < 1 are rude messages 212 | # from 1 to 10 are polite messages 213 | # and after 10 are other types! 214 | if (x < 1): 215 | print("Rude messsage") 216 | elif (x >= 1 and x <= 10): 217 | print("Polite message") 218 | else: 219 | print("Any other message") 220 | ``` 221 | 222 | ```py 223 | vegetable_market = ["onion", "tomato", "broccoli", "cabbage"] 224 | 225 | if "carret" in vegetable_market: 226 | print("Bought carret!") 227 | elif "cabbage" in vegetable_market: 228 | print("Bought cabbage!") 229 | else: 230 | print("Came back empty handed...") 231 | ``` 232 | 233 | ## Loops 234 | 235 | ### Codes 236 | - [Loop constructs](day2/loops.py) 237 | - [Sum of digits](day2/sum_of_digits.py) 238 | - [Multiplication tables](day2/multiplication_tables.py) 239 | 240 | ### Why and how of loops? 241 | - Frequently we want a program to keep doing the same thing over and over again until something happens. That’s called looping. 242 | - Let’s say you are playing a game in which you get a score of 2 points every 1 second as long as you are alive in the game. Is that an example of loop? 243 | - Say you need to print numbers from 1 to 10 to the screen, how will you do it? 244 | - We will see the following 2 types of loops: 245 | - **for**: It is used when we know how many times our loop body will get executed or can decide it before the loop starts. 246 | - **while**: It is used when the loop will break upon some condition returning false which we might not be sure when exactly that would happen. 247 | - Nested loops (loop inside a loop) are also required at places, for e.g. consider a train it has multiple compartments, and each compartment has multiple seats, so the ticket checker loops over each compartment, and in each compartment, further loops over each of the seats! 248 | 249 | ### range function 250 | 251 | - `range(n)` includes all numbers from 0 to (n - 1) 252 | - `range(1, n)` includes all numbers from 1 to (n - 1) 253 | - `range(1, n, 2)` includes all numbers from 1 to (n - 1) with a step increment of 2 254 | - You can use `list(range(...))` to show the numbers in the range used. 255 | 256 | ```py 257 | # print numbers from 1 to 10 to the screen 258 | ''' 259 | print(1) 260 | print(2) 261 | ... 262 | print(10) 263 | 264 | The above is not a good practice since our requirement 265 | might change and we might have to print from 1 to n, where n is the input. 266 | Also, the code is repititive, that is why language provides loop constructs! 267 | ''' 268 | 269 | # for loops in python do not have initialization, condition, update statement like in other langs 270 | # in keyword is used along with for, to iterate over items in a container or sequence 271 | 272 | for n in range(10): 273 | print(n, end=' ') 274 | print() # by default, end = '\n' 275 | ``` 276 | 277 | ```py 278 | # the above code prints '0 1 2 ... 9' 279 | # we want to print '1 2 3 ... 10' 280 | 281 | for n in range(1, 11): 282 | print(n, end=' ') 283 | print() 284 | ``` 285 | 286 | ```py 287 | # let us say we want to print all even numbers from 1 to 10 288 | 289 | for n in range(2, 11, 2): 290 | print(n, end=' ') 291 | print() 292 | ``` 293 | 294 | ```py 295 | # can use list operator before range, to print the items in the range 296 | print(list(range(2, 11, 2))) 297 | ``` 298 | 299 | ```py 300 | # doing the same thing using a while loop 301 | counter = 0 302 | while (counter < 10): 303 | counter += 1 304 | print(counter, end=' ') 305 | print() 306 | 307 | # NOTE: while loops usually have a statement to update the sentinel value (being checked in condition) 308 | # otherwise the loop can run infinitely, use Ctrl-C to exit the infinite loop 309 | # the loop below runs infinitely 310 | 311 | ''' 312 | counter = 0 313 | while (counter < 10): 314 | print(counter, end=' ') 315 | ''' 316 | ``` 317 | 318 | ```py 319 | ''' 320 | Program to find sum of digits of a number 321 | ''' 322 | n = int(input()) 323 | 324 | # say n = 1234, how do you compute the sum of the digits? 325 | # you see all the digits, 1, 2, 3, 4, and add them up in a go, boom => 10 is the answer 326 | 327 | # How do we program the computer to do this for us? 328 | # We should follow the same technique, right? 329 | # Loop through all the digits, and add them up one by one! 330 | # So, our computer will store the result at some place, we need to create a variable 331 | # Say sum = 0 332 | # How to find a particular digit? 333 | # n = 1234, can we say last digit is the one we get after finding remainder when n is divided by 10 334 | # i.e. n % 10 = 4, add this 4 to the sum, now sum = 4 335 | # Now, we can divide n by 10, to get n' = 1234//10 = 123 (integer division!) 336 | # We continue this process, until n becomes zero!!! 337 | # Pseudocode: 338 | ''' 339 | n = input from user 340 | sum = 0 341 | while (n > 0) 342 | d = last digit of n (i.e. n % 10) 343 | add d to sum 344 | divide n by 10 345 | print(sum) 346 | ''' 347 | ``` 348 | 349 | ```py 350 | sum = 0 351 | while (n > 0): 352 | d = n % 10 353 | sum += d # shorthand for sum = sum + d 354 | n //= 10 # shorthand for n = n//10 355 | print(sum) 356 | 357 | # Try yourself: 358 | # 1. Count digits in a number 359 | # 2. Reverse a number 360 | # 3. Find all factors of a number 361 | ``` 362 | 363 | ```py 364 | ''' 365 | Program to print multiplication tables of numbers from 1 to n 366 | ''' 367 | n = int(input()) 368 | 369 | for multiple in range(1, 11): 370 | for number in range(1, n + 1): 371 | print(number*multiple, end=' ') 372 | print() 373 | 374 | # formatted output 375 | for multiple in range(1, 11): 376 | for number in range(1, n + 1): 377 | print("%4d"%(number*multiple), end=' ') 378 | print() 379 | ``` 380 | 381 | ## Jump statements 382 | - break 383 | - continue 384 | 385 | ### Why break statement? 386 | - Let’s take a real scenario where we can use break statements. 387 | - Let us consider a repetitive task to send email to 100 employees. 388 | - Suppose after sending 10 emails, suddenly internet disconnected. What action you will perform at that time? 389 | - You can either attempt a try to send rest 90 emails, which will result in error. 390 | Alternatively, you can terminate the mailing process with a warning or error message. 391 | - Definitely, it is better to postpone or terminate the mailing process for now than sending mails further that will result in error. 392 | 393 | ```py 394 | # break and continue allow to control the flow of the loops 395 | 396 | # using break, we can go outside the loop 397 | names = ["Scaler", "Interviewbit", "scaler", "interviewbit"] 398 | for name in names: 399 | print(name) 400 | if (name == "Scaler"): 401 | break 402 | ``` 403 | 404 | ```py 405 | # using continue, we can skip a particular iteration, and go to next one 406 | for name in names: 407 | if (name == "Scaler"): 408 | continue 409 | print(name) 410 | ``` 411 | 412 | ```py 413 | # using break in nested loops 414 | # break in the inner loop just breaks out of the inner loop 415 | # outer loop will continue to run 416 | target = 'i' 417 | for name in names: 418 | print(f"{name} in outer loop") 419 | for char in name: 420 | if char == target: 421 | print(f"Found {name} with letter: {target}") 422 | print("Breaking out of the inner loop") 423 | break 424 | ``` 425 | 426 | ```py 427 | # Exercise: 428 | # Write a program to check if a given number is prime, use the break statement wisely! 429 | ``` 430 | 431 | ## Functions 432 | 433 | ### What is a function? 434 | - Consider it to be a black box that takes serveral inputs, does some processing and can return some output 435 | - To write a program, either we can have a single big piece of code file which will become difficult to maintain, so we use functions and break our code into small tasks, i.e. functions 436 | 437 | ### Why functions? 438 | - Reusability 439 | - Abstraction 440 | - To use a function, you only need to know its name and the arguments it accepts. 441 | - You need not know how it works internallly. 442 | - Modular design 443 | - Maintenance 444 | - Debugging 445 | - It becomes a lot easier if we know the exact function where the code is breaking! 446 | 447 | ### Defining and calling functions 448 | 449 | ```py 450 | def print_function(): 451 | print("This function just prints to the screen!") 452 | 453 | x = print_function() # Function which does not return anything, returns 'None' 454 | print(x) 455 | ''' 456 | Output: 457 | This function just prints to the screen! 458 | None 459 | ''' 460 | ``` 461 | 462 | ```py 463 | def sum_of_two(num_1, num_2): 464 | return num_1 + num_2 465 | 466 | res = sum_of_two(1, 100) 467 | print(res) 468 | ``` 469 | 470 | ### Functions with default arguments 471 | 472 | ```py 473 | # functions can accept arguments with default values (called as keyword arguments) 474 | def greetings(name="Scaler"): 475 | print(f"Hello from {name}") 476 | 477 | greetings() 478 | greetings("InterviewBit") 479 | ``` 480 | 481 | ```py 482 | # Exercise, complete the following function that returns maximum of three numbers 483 | # def max_of_three(num_1, num_2, num_3) 484 | ``` -------------------------------------------------------------------------------- /lecture3.md: -------------------------------------------------------------------------------- 1 | # Day 3: Basic Data Structures 2 | 3 | ## Day 2 Recap 4 | [Control Flow: Conditionals, Loops, Jump statements, functions](day3/recap.py) 5 | 6 | ### Check if given number is a prime 7 | 8 |
9 | 10 | Code 11 | 12 | 13 | ```py 14 | """ 15 | program to check if the number (say 'n') given as input is a prime 16 | a prime no. is the one which has only 1 and the numbers itself as its divisors 17 | 1 is not a prime no. 18 | eg. n = 2, 3, 5, 7, ... 19 | 20 | idea: start a loop from 2 to n/2, if n is divisble by the divisor => not prime 21 | because a no. cannot be divided by a no. > n/2 except n 22 | """ 23 | 24 | n = int(input()) 25 | checked = 0 26 | for divisor in range(2, n//2 + 1): 27 | if (n % divisor == 0): 28 | print("No is not prime!") 29 | checked = 1 30 | # no need checking further, can break the loop here itself 31 | break 32 | 33 | # the above code doesn't say that 1 is not a prime because loop won't run even once 34 | # to handle that case, we can add the extra condition: 35 | if (n == 1): 36 | print("No is not prime!") 37 | checked = 1 38 | 39 | # in cases where checked is false or equal to 0, can say it is prime! 40 | if (not checked): 41 | print("No is prime!") 42 | ``` 43 | 44 |
45 | 46 | ### Printing star pattern 47 | 48 |
49 | 50 | Code 51 | 52 | 53 | ```py 54 | """ 55 | program to print the following pattern: 56 | 57 | * 58 | * * 59 | * * * 60 | * * * * 61 | ... 62 | 63 | idea: As you can observer, we are looping in two directions, row wise and column wise 64 | 1st row has 1 star 65 | 2nd row has 2 stars 66 | 3rd row has 3 stars and so on... 67 | 68 | the outer loop would represent looping over the rows 69 | and in the inner loop, we will loop over the elements in the rows, i.e. columns 70 | 71 | Always better to use loop variable 'r' or 'row' for looping on rows 72 | and the loop variable 'c' or 'col' to loop on columns 73 | for easy understanding and debugging of your code ! 74 | """ 75 | 76 | num_rows = n 77 | for row in range(1, num_rows + 1): 78 | # r_th row will have r stars 79 | for col in range(1, row + 1): 80 | print('*', end=' ') 81 | # endline 82 | print('') 83 | 84 | # is it possible to do the same thing using one loop, think? 85 | 86 | # idea is the same: print 1 char in 1st row, 2 chars in 2nd row, ... 87 | line_num = 1 88 | printed_on_cur_row = 0 89 | while (line_num <= num_rows): 90 | if (printed_on_cur_row < line_num): 91 | print('*', end=' ') 92 | printed_on_cur_row += 1 93 | else: 94 | print('') 95 | # reset count of stars on cur_row to be zero 96 | printed_on_cur_row = 0 97 | # increment the line_num, i.e. move to next row 98 | line_num += 1 99 | ``` 100 | 101 |
102 | 103 | ### Find max of three numbers 104 | 105 |
106 | 107 | Function 1 108 | 109 | 110 | ```py 111 | """ 112 | function to return maximum of three numbers 113 | 114 | idea: let numbers be a, b, c 115 | when can a be the max? when a >= b and a >= c 116 | similarly for b and c 117 | so, write three conditions, and return the answer if that condition is true 118 | also, you can use if elif else as well! 119 | """ 120 | 121 | def maximum_of_three(num_one, num_two, num_three): 122 | if (num_one >= num_two and num_one >= num_three): 123 | return num_one 124 | if (num_two >= num_one and num_two >= num_three): 125 | return num_two 126 | if (num_three >= num_one and num_three >= num_two): 127 | return num_three 128 | return -1 129 | 130 | n1 = 3 131 | n2 = 7 132 | n3 = 1 133 | 134 | res = maximum_of_three(n1, n2, n3) 135 | print(res) 136 | ``` 137 | 138 |
139 | 140 |
141 | 142 | Function 2 143 | 144 | 145 | ```py 146 | # idea: assign max = a, now check if b >= max, max = b, again if c >= max, max = c 147 | def maximum_of_three_simple(n1, n2, n3): 148 | maxi = n1 149 | if (n2 >= maxi): 150 | maxi = n2 151 | if (n3 >= maxi): 152 | maxi = n3 153 | return maxi 154 | 155 | res = maximum_of_three(n1, n2, n3) 156 | print(res) 157 | ``` 158 | 159 |
160 | 161 | ## More on Functions 162 | [Code](day3/functions.py) 163 | 164 | ### Keyword Arguments and Positional Arguments 165 | - A function can have two types of arguments: ones with default values and those without it. 166 | - The arguments which have a default value are termed as `keyword arguments` and required ones are `positional arguments`. 167 | - These arguments should always be the last ones, i.e. All the *required (positional) arguments go first*. They are then *followed by the optional keyword arguments*. 168 | - Arguments without defaults are required otherwise you get a syntax error. 169 | - You can pass in none, some or all of the keyword arguments. 170 | - You can pass in parameters by keyword (name defined for argument). 171 | 172 |
173 | 174 | Function with keyword arguments (code) 175 | 176 | 177 | ```py 178 | # for eg the print function we use has 'sep' as a keyword argument which is '\n' by default 179 | 180 | # below is also a way you can document your function using docstrings 181 | def distance_travelled(t, u = 0, g = 9.81): 182 | """ 183 | Function distance_travelled calculates the distance travelled by an object 184 | with initial speed u, in a time interval of t, where acceleration due to gravity is g 185 | 186 | input: t (time taken), u (initial speed) g (acceleration due to gravity) 187 | output: distance travelled 188 | 189 | Example: 190 | >>> distance_travelled(1.0) 191 | 192 | 4.905 193 | """ 194 | d = u*t + 0.5 * g * t**2 195 | return d 196 | 197 | print(distance_travelled(2.0)) 198 | print(distance_travelled(2.0, u = 1.0)) 199 | print(distance_travelled(2.0, g = 9.7)) 200 | print(distance_travelled(g = 9.7, t = 2.0)) 201 | ``` 202 | 203 |
204 | 205 | ### Function scope 206 | 207 | ```py 208 | # scope inside a function is different than the one outside it 209 | # inside function scope, you can access the outer scope variables but cannot change them 210 | 211 | def set_name(input_name): 212 | name = input_name 213 | print(f"Name inside the function: {name}") 214 | 215 | set_name("Scaler") 216 | # print(name) # NameError: this variable is not defined 217 | ``` 218 | 219 | ### Exercise 220 | 221 |
222 | 223 | Guess output of the code 224 | 225 | 226 | ```py 227 | # Exercise: What should be the output for this piece of code? 228 | # NEVER USE ARGUMENTS WITH LISTS AS DEFAULT VALUES!!! 229 | def add_char_to_list(char, lst = []): 230 | lst.append(char) 231 | return lst 232 | add_char_to_list('s') 233 | add_char_to_list('c') 234 | add_char_to_list('a') 235 | add_char_to_list('l') 236 | add_char_to_list('e') 237 | print(''.join(add_char_to_list('r'))) 238 | ``` 239 | 240 |
241 | 242 | ## Containers 243 | 244 | - [Lists](day3/lists.py) 245 | - [Tuples](day3/tuples.py) 246 | - [Sets](day3/sets.py) 247 | - [Dictionaries](day3/dictionaries.py) 248 | 249 | ## Lists 250 | 251 | ```py 252 | # lists: container objects used to store related items together 253 | # let us say you were to input n numbers from user and find their sum, average, etc. 254 | # also you need the ability to sort the numbers etc 255 | # so you need some data type to store them easily, take input and print some required data 256 | 257 | number_list = [] 258 | number_list = [10, 4, 1, 5] 259 | print(type(number_list)) 260 | ``` 261 | 262 | ```py 263 | # 0-based indexing to access elements in the list 264 | # order is retained in the list! 265 | first_num = number_list[0] 266 | last_num = number_list[-1] 267 | print(f"First: {first_num}, Last: {last_num}") 268 | ``` 269 | 270 | ```py 271 | # common methods on lists 272 | print(f"Number list: {number_list}") 273 | 274 | num_count = len(number_list) 275 | print(f"Count: {num_count}") 276 | 277 | number_list.append(7) 278 | print(f"Appended 7: {number_list}") 279 | 280 | number_list.insert(1, 6) 281 | print(f"Insert 6 at index 1: {number_list}") 282 | 283 | number_list.pop() 284 | print(f"Removed the last element: {number_list}") 285 | ``` 286 | 287 | ```py 288 | # lists are mutable, can change the elements in-place 289 | # sorting lists, sorted method returns a new list 290 | ordered_num_list = sorted(number_list) 291 | print(f"Ordered number list: {ordered_num_list}") 292 | print(f"Original number list: {number_list}") 293 | 294 | # sorting in place, descending order 295 | number_list.sort(reverse=True) 296 | print(f"Original number list: {number_list}") 297 | # reversing a list in-place 298 | number_list.reverse() 299 | print(f"Reversed number list: {number_list}") 300 | ``` 301 | 302 | ```py 303 | # extending one list into another 304 | l1 = [1, 2, 3, 4] 305 | l2 = [5, 6, 7, 10] 306 | l1.extend(l2) 307 | print(l1) 308 | print(l2) 309 | ``` 310 | 311 | ```py 312 | # checking if an item is present in a list (in keyword) 313 | print(5 in l1) 314 | print(8 in l2) 315 | ``` 316 | 317 | ```py 318 | # split and join 319 | input_str = "1 2 3 4 5 6" 320 | input_list = input_str.split() 321 | print(input_list) 322 | 323 | print(','.join(input_list)) 324 | ``` 325 | 326 | ## Tuples 327 | 328 | ```py 329 | # tuples are used to keep track of related but different items 330 | # they are immutable, you cannot change the items in it once created! 331 | # a use-case could be to store a row in a spreadsheet, given that 332 | # we need read-only snapshot of data 333 | 334 | point = () 335 | # point = collection of x, y and z coordinates! 336 | point = (3, 4, 5) 337 | print(point) 338 | print(type(point)) 339 | ``` 340 | 341 | ```py 342 | # checking for existence of an item 343 | print(3 in point) 344 | print(6 in point) 345 | ``` 346 | 347 | ```py 348 | 349 | # access item using index as well 350 | print(f"x = {point[0]}, y = {point[1]}, z = {point[2]}") 351 | 352 | # point[0] = 10 # TypeError: 'tuple' object does not support this assignment 353 | ``` 354 | 355 | ```py 356 | # to create single item tuple, we need to give a comma after the item 357 | single_element = (1) 358 | print(type(single_element)) # 359 | 360 | single_element = (1, ) 361 | print(single_element) 362 | print(type(single_element)) # 363 | ``` 364 | 365 | ```py 366 | # unpacking tuple data 367 | x, y, z = point 368 | print(x, y, z) 369 | 370 | # functions can as well return multiple values with the help of tuples 371 | ``` 372 | 373 | ## Sets 374 | 375 | ```py 376 | # sets help to store data in an unsorted way 377 | # an item can only be present once in a set, i.e. no duplicates 378 | # membership test is very fast 379 | # other powerful operations provided are: union, difference and intersection 380 | 381 | prime_set = set() 382 | prime_set.add(1) 383 | prime_set.add(2) 384 | prime_set.add(3) 385 | prime_set.add(11) 386 | # order is not preserved in a set 387 | print(f"Prime set: {prime_set}") 388 | ``` 389 | 390 | ```py 391 | # remove an item from a set 392 | prime_set.discard(1) 393 | print(f"Prime set: {prime_set}") 394 | ``` 395 | 396 | ```py 397 | # x = prime_set[0] # cannot access set items using an index 398 | # prime_set.sort() # cannot sort items in a set 399 | # sorted method can still be used as that will convert set to a list 400 | ``` 401 | 402 | ```py 403 | # single element set 404 | s = {1} 405 | print(s) 406 | print(type(s)) 407 | 408 | s = {} 409 | print(type(s)) # 410 | # to create empty set, rather use set constructor 411 | s = set() 412 | print(type(s)) # 413 | ``` 414 | 415 | ```py 416 | prime_set = {2, 3, 5, 5, 3, 7} 417 | print(prime_set) # duplicate values not present 418 | ``` 419 | 420 | ```py 421 | # sets internally use hashing to store the elements and check if it is present or not 422 | # a numerical value is associated with any item in the set, try using hash() method 423 | # hash() function works only on immutable data types, so you cannot create a set of mutable types 424 | 425 | names = {"scaler", "interviewbit", "scaler"} 426 | print(names) 427 | # both the following hash values will come out to be same! although values can change 428 | # depending on when the program is run 429 | print(hash("scaler")) 430 | print(hash("scaler")) 431 | 432 | # set_of_lists = {[1, 2, 3], [1, 2, 3, 4]} # TypeError: unhashable type: 'list' 433 | ``` 434 | 435 | ```py 436 | # we can convert a list into a set using the set constructor 437 | names = ["scaler", "interviewbit", "scaler"] 438 | names_set = set(names) 439 | print(names_set) 440 | 441 | # update is used to update set with another sequence 442 | prime_set.update(names_set) 443 | print(prime_set) 444 | prime_set.update("scaler") 445 | # since string is a sequence, each of its characters will get added to the set! 446 | print(prime_set) 447 | 448 | # union (|), intesection (&), difference (^) 449 | ``` 450 | 451 | ## Dictionaries 452 | 453 | - Let us say we need to store names, courses and grade details for students 454 | - Storing separate lists for each of them would become difficult to keep track of 455 | - Also retrieving data will also be not that efficient 456 | - It is always better to use a single data structure to store similar data 457 | - We can use a dictionary here, which has the student name as the key! 458 | - Lists have an order based on the index but dict doesn't guarantee any order. 459 | - You could write a program to find the most frequent word in a huge text file very easily using dict! 460 | 461 | ```py 462 | # dict allows us to store data in (key, value) pairs 463 | # themselves are mutable but can contain only immutable types as keys, like sets 464 | # very useful for accessing data based on a key, quickly 465 | 466 | # creating empty dict 467 | day_mapping = {} 468 | day_mapping = dict() 469 | ``` 470 | 471 | ```py 472 | # dict with items (key, value) pairs 473 | day_mapping = { 474 | "Monday": 1, 475 | "Tuesday": 2, 476 | "Wednesday": 3, 477 | "Thursday": 4, 478 | "Friday": 5, 479 | "Saturday": 6, 480 | "Sunday": 0 481 | } 482 | print(len(day_mapping)) # 7 483 | ``` 484 | 485 | ```py 486 | # items can be accessed based on the key, not the index 487 | print(day_mapping["Wednesday"]) # 3 488 | print(day_mapping.get("Sunday")) 489 | print(day_mapping.get("sunday")) # None, because the key is not present 490 | ``` 491 | 492 | ```py 493 | # updating value for a particular key 494 | day_mapping["Sunday"] = 7 495 | # adding another key 496 | day_mapping["Default"] = 0 497 | ``` 498 | 499 | ```py 500 | # keys, values and items 501 | print(day_mapping.keys()) 502 | print(day_mapping.values()) 503 | print(day_mapping.items()) 504 | 505 | # removing a particular key 506 | del(day_mapping["Default"]) 507 | print(day_mapping.keys()) 508 | ``` 509 | 510 | ## Mutability Summary 511 | - Basic Types: `int`, `float`, `decimal`, `str`, `bool` all are immutable 512 | - Container Types: `list`, `set` and `dict` are mutable while `tuple` is not 513 | 514 | ## List Comprehensions 515 | 516 | ```py 517 | # given a list of strings, find lengths of each of them 518 | names = ["scaler", "interviewbit"] 519 | len_list = [] 520 | for name in names: 521 | len_list.append(len(name)) 522 | print(len_list) 523 | ``` 524 | 525 | ```py 526 | # using list comprehension 527 | len_list = [len(name) for name in names] 528 | len_list = [("length", len(name)) for name in names] 529 | print(len_list) 530 | # with odd lengths 531 | len_list = [("length", len(name)) for name in names if len(name) % 2 == 1] 532 | print(len_list) 533 | ``` 534 | 535 | ```py 536 | # sum of all even numbers from 1 to 100 537 | sum_even = sum([num for num in range(1, 101) if num % 2 == 0]) 538 | print(sum_even) 539 | ``` -------------------------------------------------------------------------------- /lecture4.md: -------------------------------------------------------------------------------- 1 | # Day 4: Organizing Codes and Dependency Management 2 | 3 | - Modules and packages 4 | - Installing libraries 5 | - Virtual Environments -------------------------------------------------------------------------------- /lecture5.md: -------------------------------------------------------------------------------- 1 | # Day 5: File I/O: Reading and Writing Text, CSV, JSON files 2 | 3 | ## Working with Text Files 4 | 5 | - Used to store data such that it can be retrieved any time 6 | - To read or write from a file, the following operations take place: 7 | 1. Open a file 8 | 2. Perform Read or write operations 9 | 3. Close the file 10 | 11 | ### Open a file 12 | 13 | ```py 14 | f = open('hello.txt', 'r') 15 | ``` 16 | 17 | - First argument is the string containing file name 18 | - Second argument is the file opening mode. (`r`, `w`, `a`, etc.) 19 | - Default, files are opened in text mode. 20 | 21 | ### Reading from file 22 | 23 | ```py 24 | f.read(5) # read next 5 bytes 25 | f.readline() # read the entire line 26 | f.readlines() # read the entire file and return list of lines 27 | f.tell() # get the current file position 28 | f.seek(0) # bring file cursor to initial position 29 | ``` 30 | ### Writing to file 31 | 32 | ```py 33 | f.write("hello world\n") 34 | ``` 35 | 36 | ### Closing a file 37 | 38 | - Frees up the resources tied with the file 39 | 40 | ```py 41 | f.close() 42 | ``` 43 | 44 | - Need to worry about exceptions if any operation on file is running 45 | - Use a `try...finally` block of code 46 | 47 | ## Open file using context manager 48 | 49 | - Need not close the file explicitly 50 | 51 | ```py 52 | with open('hello.txt') as f: 53 | # perform file operations 54 | ``` 55 | 56 | ## Working with CSV Files 57 | 58 | - CSV (Comma Separated Values) format is one of the most simplest ways to store tabular data. 59 | - Elements are separated by a delimiter, generally, a comma `,`. 60 | - The python's `csv` module makes it easier to operate on such files. 61 | 62 | ### Reading CSV File 63 | 64 | ```py 65 | import csv 66 | with open('marks.csv', 'r') as file: 67 | reader = csv.reader(file) 68 | for row in reader: 69 | print(row) 70 | ``` 71 | 72 | - Explore `skipinitialspace` attribute in the reader function. 73 | - There can be many other attributes specified and can make code difficult to maintain, so to solve this `dialect` is provided as another optional parameter, which groups together many formatting patterns. 74 | 75 | ### Writing to CSV File 76 | 77 | ```py 78 | import csv 79 | with open('marks.csv', 'w') as file: 80 | writer = csv.writer(file) 81 | writer.writerow(["Roll No.", "Name", "Marks"]) 82 | writer.writerow([1, "abc", 95]) 83 | writer.writerow([2, "def", 97]) 84 | ``` 85 | 86 | - You can also try creating rowlist as list of lists and use the `writer.writerows` function. 87 | 88 | ### Read file as a dictionary 89 | 90 | ```py 91 | import csv 92 | with open('marks.csv', 'r') as file: 93 | csv_dict = csv.DictReader(file) 94 | for row in csv_dict: 95 | print(row) 96 | ``` 97 | 98 | - Similarly, can try exploring `DictWriter`. 99 | - Also try to explore the `Pandas` library which is a popular library for data manipulation and analysis. 100 | 101 | ## Working with JSON Files 102 | 103 | - Saving more complex data types like nested lists and dictionaries, parsing and serializing becomes complicated. 104 | - Python allows us to use the popular data interchange format JSON (JavaScript Object Notation) through a module `json`. 105 | - Converting python data to string is known as *serializing*. 106 | - Reconstructing the data from the string representation is called *deserializing*. 107 | 108 | ### Reading json from file 109 | 110 | ```py 111 | import json 112 | with open('marks.json') as file: 113 | data = json.load(file) 114 | print(data) # dict 115 | ``` 116 | 117 | - `json.loads` can be used to convert string to dict. 118 | 119 | ### Writing json to file 120 | 121 | ```py 122 | import json 123 | 124 | marks_dict = { 125 | "roll_no": 12, 126 | "name": "abc", 127 | "marks": 99 128 | } 129 | with open('marks.json', 'w') as json_file: 130 | json.dump(marks_dict, json_file) 131 | ``` 132 | 133 | - `json.dumps` can be used to convert dict to string. 134 | - Can pass `indent` and `sort_keys` properties to pretty print the json data. 135 | 136 | [Example code](day5/todos.py) 137 | 138 | ## Other libraries and documentation 139 | 140 | - For manipulating path: [pathlib](https://docs.python.org/3/library/pathlib.html) and [os.path](https://docs.python.org/3/library/os.path.html) 141 | - For copying, moving files and other file operations: [shutil](https://docs.python.org/3/library/shutil.html) 142 | - Serializing python objects to disk: [pickle](https://docs.python.org/3/library/pickle.html) 143 | - [Data compression and archiving](https://docs.python.org/3/library/archiving.html) 144 | - [File formats](https://docs.python.org/3/library/fileformats.html) 145 | - [Logging](https://docs.python.org/3/library/logging.html) -------------------------------------------------------------------------------- /lecture7.md: -------------------------------------------------------------------------------- 1 | # Advanced Python 2 | 3 | What have we covered so far 4 | --------------------------- 5 | 6 | - Data Types: int, float, bool, complex, str 7 | - Containers: tuple, list, dict, set 8 | - Operators: Arithmetic (`+ - * / % // **`), Logical (`and or not`) 9 | - Flow Control: `if-elif-else`, `for` and `while` loops, `break`, `continue` 10 | - Functions: defining and calling functions 11 | - Organizing Python Code: Modules, Packages and Virtualenv 12 | - File I/O: Reading and writing files, CSVs, Json 13 | - Hands on Project Building: Todo CLI app 14 | 15 | What else does Python offer 16 | --------------------------- 17 | - Object Oriented Programming 18 | - Functional Programming 19 | - Syntactic Sugar - decorators, generators, context managers 20 | - Fancy metaprogramming - metaclasses, iterators, descriptors, import hooks, monkey patching 21 | - Extensive Standard Library - regex, os, math, random, cli, file, string, date, compression, performance, logging, threading, http 22 | - Extensive Ecosystem - Machine Learning and Data Analysis, DevOps, Web Frameworks 23 | 24 | 25 | What really matters 26 | ------------------- 27 | 28 | - What can you build with your skills 29 | - The positive impact you can bring 30 | 31 | Build Real SaaS Products using Django & Python 32 | ---------------------------------------------- 33 | 34 | - Starting from tomorrow - 15th Sept 2020 35 | - Timing: 6.30 pm to 7.30 pm (GMT+5.30) 36 | - https://www.youtube.com/c/ScalerAcademy/ 37 | 38 | Resources 39 | --------- 40 | 41 | - https://docs.python.org/3/tutorial/index.html 42 | - https://docs.python.org/3/library/index.html 43 | - https://www.youtube.com/playlist?list=PLIoJ3PkAEIvwnkJjvixHIYOH0ErGKBxFc -------------------------------------------------------------------------------- /todo_cli/README.md: -------------------------------------------------------------------------------- 1 | # Todo Command Line Application 2 | 3 | ## Create a virtual environment (optional) 4 | 5 | Python 3: 6 | ``` 7 | $ pip3 install virtualenv 8 | $ virtualenv -p python3 venv 9 | ``` 10 | 11 | Activate the environment: 12 | 13 | ``` 14 | source venv/bin/activate 15 | ``` 16 | 17 | ## Use cases 18 | 19 | - Create a todo list 20 | - Add, Edit and Delete todo items in a todo list 21 | - Mark todo items as complete and incomplete 22 | - Show all todo items in a todo list 23 | 24 | ## Commands 25 | 26 | 1. `list show` 27 | 2. `list use list_name` 28 | 3. `list create list_name` 29 | 3. `todo add item_names` 30 | 4. `todo all` 31 | 5. `todo edit item_id new_item_name` 32 | 6. `todo remove item_id` 33 | 7. `todo complete item_id` 34 | 8. `todo incomplete item_id` 35 | 9. `help` 36 | 10. `quit` 37 | 38 | ## JSON Files 39 | 40 | ### lists.json 41 | 42 | - stores a list of todo lists 43 | - a todo list is a dict having title and created_at field 44 | 45 | OR 46 | 47 | - stores a dict of todo lists having title as key and file name and time of creation as nested dict 48 | 49 | ### list.json 50 | 51 | - list refers to the todo list name 52 | - stores a list of todo item 53 | - each todo item is a dict having title, created_at, and completed field. -------------------------------------------------------------------------------- /todo_cli/app.py: -------------------------------------------------------------------------------- 1 | from commands import commands_dict 2 | 3 | def parse(command): 4 | """ 5 | Takes the command as input and returns the command name and args 6 | """ 7 | cmd_list = command.split() 8 | cmd_type = cmd_list[0] 9 | if (cmd_type == 'help' or cmd_type == 'quit'): 10 | return cmd_type, [] 11 | elif (cmd_type == 'list'): 12 | cmd_name = cmd_list[1] 13 | if (cmd_name in ['show', 'use', 'create']): 14 | return cmd_name, cmd_list[2:] 15 | else: 16 | return 'invalid', [] 17 | elif (cmd_type == 'todo'): 18 | cmd_name = cmd_list[1] 19 | if (cmd_name in ['add', 'all', 'edit', 'remove', 'complete', 'incomplete']): 20 | return cmd_name, cmd_list[2:] 21 | else: 22 | return 'invalid', [] 23 | else: 24 | return 'invalid', [] 25 | 26 | def main(): 27 | print('Started the Todo application...') 28 | current_list = '' 29 | while(1): 30 | # take the command as input from the user 31 | command = input('$ ') 32 | command_name, command_args = parse(command) 33 | # print(command_name, command_args) 34 | if (command_name == 'quit'): 35 | break 36 | elif (command_name == 'help'): 37 | with open('help.txt', 'r') as help_file: 38 | print(help_file.read()) 39 | elif (command_name == 'invalid'): 40 | print('Please enter a valid command, use help command to display all!') 41 | elif (command_name == 'use'): 42 | file_name = commands_dict[command_name](command_args) 43 | if (file_name == -1): 44 | print('This is not a valid list name!') 45 | current_list = '' 46 | else: 47 | print('Successfuly chosen this list...') 48 | current_list = file_name 49 | elif (command.split()[0] == 'todo'): 50 | # todo type of command 51 | command_args.insert(0, current_list) 52 | commands_dict[command_name](command_args) 53 | else: 54 | commands_dict[command_name](command_args) 55 | 56 | if __name__ == '__main__': 57 | main() -------------------------------------------------------------------------------- /todo_cli/commands/__init__.py: -------------------------------------------------------------------------------- 1 | import commands.lists 2 | import commands.todos 3 | 4 | commands_dict = { 5 | 'show': lists.show_lists, 6 | 'use': lists.use_list, 7 | 'create': lists.create_list, 8 | 'add': todos.add_item, 9 | 'all': todos.show_items, 10 | 'edit': todos.edit_item, 11 | 'remove': todos.remove_item, 12 | 'complete': todos.complete_item, 13 | 'incomplete': todos.incomplete_item 14 | } -------------------------------------------------------------------------------- /todo_cli/commands/lists.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | import json 3 | from datetime import datetime 4 | 5 | FILE_NAME = 'lists.json' 6 | 7 | def show_lists(args): 8 | with open(FILE_NAME, 'r') as lists_json: 9 | try: 10 | data = json.load(lists_json) 11 | for index, todo_list in enumerate(data.keys()): 12 | print(index + 1, data[todo_list]['title']) 13 | except: 14 | print('Some error occurred!') 15 | 16 | def use_list(args): 17 | list_name = args[0] 18 | with open(FILE_NAME, 'r') as lists_json: 19 | try: 20 | data = json.load(lists_json) 21 | if (data.get(list_name)): 22 | return f'{list_name}.json' 23 | else: 24 | return -1 25 | except: 26 | print('Some error occurred!') 27 | 28 | def create_list(args): 29 | list_name = args[0] 30 | # print(os.path.abspath('.')) 31 | new_list = {} 32 | with open(FILE_NAME, 'r+') as lists_json: 33 | try: 34 | data = json.load(lists_json) 35 | # print(data) 36 | # check if file already exists 37 | if (data.get(list_name)): 38 | print('List already exists! Try a different name...') 39 | else: 40 | # update the new_list dict 41 | new_list = { 42 | 'title': list_name, 43 | 'created_at': datetime.now().strftime("%d/%m/%Y %H:%M:%S") 44 | } 45 | data[list_name] = new_list 46 | with open(f'lists/{list_name}.json', 'w') as new_list: 47 | # empty list 48 | new_list.write('[\n]') 49 | print('Successfully created the new list!') 50 | # add to the lists.json 51 | lists_json.seek(0) 52 | json.dump(data, lists_json, sort_keys=True, indent=True) 53 | except: 54 | print('Some error occurred!') -------------------------------------------------------------------------------- /todo_cli/commands/todos.py: -------------------------------------------------------------------------------- 1 | import json 2 | from datetime import datetime 3 | 4 | def set_list(list_name): 5 | if (list_name == ''): 6 | print('Please select a given list before this action') 7 | return list_name 8 | 9 | def get_data(list_file_name): 10 | """ 11 | Get the deserialized data from the todo list json file 12 | """ 13 | with open(f'lists/{list_file_name}', 'r') as json_file: 14 | data = json.load(json_file) 15 | return data 16 | 17 | def update_data(list_file_name, new_data): 18 | """ 19 | Update the content of the todo list json file 20 | with the serialized version of 'new_data' 21 | """ 22 | with open(f'lists/{list_file_name}', 'w') as json_file: 23 | json.dump(new_data, json_file, sort_keys=True, indent=True) 24 | 25 | def add_item(args): 26 | """ 27 | Adds a todo item to the todo list 28 | """ 29 | list_name = set_list(args[0]) 30 | if (not list_name): 31 | return 32 | title = args[1] 33 | data = get_data(list_name) 34 | new_todo = { 35 | 'title': title, 36 | 'created_at': datetime.now().strftime("%d/%m/%Y %H:%M:%S"), 37 | 'completed': False 38 | } 39 | data.append(new_todo) 40 | update_data(list_name, data) 41 | 42 | def show_items(args): 43 | """ 44 | Prints all the todo items in the currently chosen todo list 45 | """ 46 | list_name = set_list(args[0]) 47 | if (not list_name): 48 | return 49 | data = get_data(list_name) 50 | complete = 0 51 | if (len(data) == 0): 52 | print('No todos in the list, why dont you add one?') 53 | else: 54 | for index, todo_item in enumerate(data): 55 | print(index + 1, todo_item['title']) 56 | if (todo_item['completed']): 57 | complete += 1 58 | print(f'{complete}/{len(data)} completed!') 59 | 60 | def edit_item(args): 61 | """ 62 | Edit a particular todo item 63 | """ 64 | list_name = set_list(args[0]) 65 | if (not list_name): 66 | return 67 | item_id = int(args[1]) 68 | new_title = args[2] 69 | data = get_data(list_name) 70 | updated_todo = { 71 | 'title': new_title, 72 | 'created_at': datetime.now().strftime("%d/%m/%Y %H:%M:%S"), 73 | 'completed': False 74 | } 75 | data[item_id - 1] = updated_todo 76 | update_data(list_name, data) 77 | 78 | def remove_item(args): 79 | """ 80 | Remove a todo item 81 | """ 82 | list_name = set_list(args[0]) 83 | if (not list_name): 84 | return 85 | item_id = int(args[1]) 86 | data = get_data(list_name) 87 | data.pop(item_id - 1) 88 | update_data(list_name, data) 89 | 90 | def complete_item(args): 91 | """ 92 | Mark a todo item as completed 93 | """ 94 | list_name = set_list(args[0]) 95 | if (not list_name): 96 | return 97 | item_id = int(args[1]) 98 | data = get_data(list_name) 99 | data[item_id - 1]['completed'] = True 100 | update_data(list_name, data) 101 | 102 | def incomplete_item(args): 103 | """ 104 | Mark a todo item as incomplete 105 | """ 106 | list_name = set_list(args[0]) 107 | if (not list_name): 108 | return 109 | item_id = int(args[1]) 110 | data = get_data(list_name) 111 | data[item_id - 1]['completed'] = False 112 | update_data(list_name, data) 113 | -------------------------------------------------------------------------------- /todo_cli/help.txt: -------------------------------------------------------------------------------- 1 | The following commands are available: 2 | 1. list show => shows all the lists available 3 | 2. list use list_name => use a given list 4 | 3. list create list_name => create a list with given name 5 | 3. todo add item_names => add a todo item to the selected list 6 | 4. todo all => show all the todo items in the chosen list 7 | 5. todo edit item_id new_item_name => edit the todo item providing the id and new title 8 | 6. todo remove item_id => remove a todo item 9 | 7. todo complete item_id => mark a todo item as completed 10 | 8. todo incomplete item_id => mark a todo item as incomplete 11 | 9. help => prints this... 12 | 10. quit => exit the application -------------------------------------------------------------------------------- /todo_cli/lists.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } --------------------------------------------------------------------------------