Pragmatic Python III

Reinforcement

Shuvo Saha
intelligentmachines
12 min readAug 31, 2020

--

This is part 3 of the series. To go back to part 1, click here.

You’re almost on your way to becoming an angry man/woman sitting in front of a desk puzzled over why his/her code doesn’t work now when it worked 5 minutes ago.

Test Yourself

We intentionally left out two building blocks in the last part because they build on what we’ve learned so far. So before we begin, I want you to solve these problems by yourself on Repl.it or any online IDE of your choice using the things we’ve learned up till now. Make sure your code accepts different inputs and still works.

1. Given a set of numbers in a list such as [1,2,2,41,23,1], calculate the average. Does the same code work for [2,-1,0,42,1]?2. Given two lists of different names ["Martha", "Sarah", "Derek"] and ["Virgo", "Derek", "Ergo"] can you find the common names and the number of common names? Will it work for two lists with no same names and all same names?3. Calculate income tax for any given income by adhering to the below rules:
I. First $10,000 - 0% Interest
II. Next $10,000 - 10% Interest
III. 20% Interest for the remaining sum.
According to these rules,$45000 would have an income tax of ($10000*0% + $10000*10% + $25000*20%) $6000.

These aren’t exactly very beginner-friendly so it’s ok if you struggle. You’re only using half the tools Python gives you so its sort of like building a paper plane with one hand.

Solutions

1. Given a set of numbers in a 6 member list such as [1,2,2,41,23,1], calculate the average. Does the same code work for other 6 member lists such as [2,-1,0,42,1,2]?

If you remember looping through a list using a for loop, this should be easy. We store the value for the sum in a variable and add every member of the list one by one. Then we just divide the value by 6. This works for any numerical list.

question_list = [1,2,2,41,23,1]
sum = 0
for number in question_list:
sum += number
average = sum/6
print(average)

Note that I wrote sum += number instead of sum = sum+number which is a fancy way of writing the same thing (known as syntactic sugar). This works for all numerical operators like sum = sum*number which becomes sum*=number.

2. Given two lists of different names ["Martha", "Sarah", "Derek"] and ["Virgo", "Derek", "Ergo"] can you find the number of common names? Will it work for two lists with no same names and all same names?

This seems complex until you realize that you can use a nested loop, a loop within a loop. All we need to do is compare every member of list B with the 1st member of list A, then for the 2nd member and so on.

list_a = ["Martha", "Sarah", "Derek"]
list_b = ["Virgo", "Derek", "Ergo"]
common_names = 0
for person in list_a:
for other_person in list_b:
if person == other_person:
common_names+=1
print(common_names)

What happens here then?

  1. We start by looping through every name on the first list.
  2. For the first person in the first list (Martha), we loop through every name in the second list.
  3. We do the same for every name in the first list and only add 1 to the common name count when both names match.
3. Calculate income tax for any given income by adhering to the below rules:
I. First $10,000 - 0% Interest
II. Next $10,000 - 10% Interest
III. 20% Interest for the remaining sum.

This boils down to breaking down the problem and doing it bit by bit to build up the solution.

We can first deduct 10,000 to find out if there is any remainder. Let’s take $60,500 as a test number.

income = 60500
tax = 0
first_tax_rate = 0
second_tax_rate = 0.1
third_tax_rate = 0.2
first_sub = income - 10000

Usually, it’s good practice to use variables and refer to those instead of hardcoding numbers. This allows us to change one variable to influence the many places it may be used e.g. we can change the tax rate variable and our code will work as intended.

If the result of the subtraction is negative, that means we have less than $10,000 and we can just multiply the first tax rate with our income. If it is positive that means it is greater than $10,000 and we multiply $10,000 by the first tax rate.

income = 60500
tax = 0
first_tax_rate = 0
second_tax_rate = 0.1
third_tax_rate = 0.2
first_sub = income - 10000
if first_sub > 0:
tax += 10000*first_tax_rate
else:
tax += income*first_tax_rate

We continue with this logic for the second tax rate. The second block (highlighted in bold below) is identical to the first. We do another subtraction to see if deducting another $10,000 results in any remainder. If it doesn’t, that means we have less than $20,000 and we calculate the tax on the excess. We take care to deduct $10,000 in the else statement because since we’ve gotten to the second block, we already calculated the tax on this $10,000.

income = 60500
tax = 0
first_tax_rate = 0
second_tax_rate = 0.1
third_tax_rate = 0.2
first_sub = income - 10000
if first_sub > 0:
tax += 10000*first_tax_rate
second_sub = first_sub - 10000
if second_sub > 0:
tax += 10000 * second_tax_rate
else:
tax += (income-10000) * second_tax_rate
else:
tax += income*first_tax_rate

Note that we still have the third tax rate to go. Note that if the second subtraction is greater than 0, that means we have a value greater than $20,000. We just need to deduct $20,000 from the income and multiply that with the third tax rate.

income = 60500
tax = 0
first_tax_rate = 0
second_tax_rate = 0.1
third_tax_rate = 0.2
first_sub = income - 10000
if first_sub > 0:
tax += 10000*first_tax_rate
second_sub = first_sub - 10000
if second_sub > 0:
tax += 10000 * second_tax_rate
tax += (income-20000) * third_tax_rate else:
tax += (income-10000) * second_tax_rate
else:
tax += income*first_tax_rate
print(tax)
Recursion is a very interesting programming quirk where you can make a piece of code call itself to solve a problem. In certain cases, solving a problem using recursion where we iterate over something is very efficient. An example would be searching through a file system.

Finishing the House

Thankfully, Python has many ways to make our lives easier; you can do things like comparisons, finding statistical values, and financial calculations in one line of code nowadays thanks to the work of all those coders before you.

Functions & Modules

Functions are reusable pieces of code. This is extremely useful when you need to reuse certain sections of code on multiple things e.g. calculating the income tax for every employee in your company.

You can make functions yourself or use some really useful premade functions that others made and compiled in the form of Python libraries. Here is an example of a square root function in Python:

def square_root(x):
return x ** (1/2)

A function has a few parts to it. The first is typing def followed by the function name. The next is the arguments. These are typed in brackets and can be of two types — positional arguments (args) and keyword arguments (kwargs). These arguments are what the function operates on. Next is the return statement which tells Python what to output. We can then call it on any number (make sure to use the print statement to see the output).

square_root(5)
square_root(25)

Functions are extremely useful, especially for performing similar operations on multiple values. Python has some built-in functions as well. One of these is the len() function that returns the length of a string or sequence. Using len() is very easy too.

len("string")

Let’s make an average function using the first question in our previous exercise and len().

def average(question_list):
sum = 0
length = len(question_list)
for number in question_list:
sum += number
average = sum/length
return average
average_value = average([1,2,3,5,1])
print(average_value)

Note that the only difference is the new length variable. We take an argument called question_list , which is a list, and we operate on this question_list and return the average value. We can be fancier and name our arguments, take multiple arguments, and also set default values.

def root(number = 0, power = 2):
return number ** (1/power)

This function is more robust than our previous square root function. It takes two arguments: a “number” and “power” keyword argument. The default value of these are 0 and 2. So even if the user forgets to put in the value, the function will default to a square root of 0. Note that unless you refer to the keyword by using the =, Python would be picky about the position. So, these would output different things as the first argument would always be the number and the second would be the power:

root(5,2)
root(2,5)

Since we used keyword arguments, we can do the following instead and they’d both output the same value.

root(power = 5, number = 2)
root(number = 2, power = 5)

Taking user input can also be achieved using a default Python function.

name = input()

So we can make our root function work on any value the user types. Unfortunately, this input function interprets inputs as strings, so we need another Python function int() to turn the input into an integer. We wrap our input() function with an int() function like so:

def root(number = 0, power = 2):
return number ** (1/power)
user_number= int(input("Give me a number: "))
user_power = int(input("Give me a power: "))
user_root = root(number = user_number, power = user_power)
print("Your root is")
print(user_root)

Libraries enhance Python’s flexibility and power by giving you pre-made functions and objects. Python is so popular that there’s probably a library for anything you want to do. For mathematics, there’s Numpy, Math, and Scipy. For data analysis and manipulation that’ll blow Excel out of the water, there’s Pandas. For visualizations, there’s Plotly, Matplotlib, Bokeh, Seaborn, etc. For machine learning, there’s Tensorflow, Keras, Pytorch, etc. Libraries are really easy to use and import.

import numpy as np
import math

Once imported, library functions will usually work with their name followed by a period. The as allows us to rename the library as we wish. This is particularly helpful for libraries with long names. Developers also have preferred shorthand such as pd for Pandas and np for Numpy.

np.average([5,20,30])
math.fabs(-50)

The np.average function does what our previous function did but faster because Numpy runs on C (a more complex but faster programming language). For more information on useful libraries, Python’s docs and Google is your friend.

Remember recursion in that meme above? We can make a recursion function now. All recursion functions will usually call the function itself in the definition.

def factorial(x):
if x == 1:
return 1
else:
return (x * factorial(x-1))
num = int(input("Input number for factorial: "))
print(factorial(num))

It’s easier to think about a number in your head when trying to think recursively.

Source: Programiz

Objects/Classes

Objects are containers consisting of variables (properties) and functions (known as methods). If an object is a Mazda RX-7, for example, a class would be a car. Classes simply contain instructions for how those objects are made.

Object-Oriented Programming (OOP) is a programming ideology that’s quite popular among software developers. The idea is to think about everything in terms of real-life objects. This can be a helpful way to structure your code when you are working with things that can be categorized easily.

To make an object, we first need to define the class.

class Car:

def __init__(self, manufacturer = "Unknown", horsepower = 0):
self.manufacturer = manufacturer
self.horsepower = horsepower

def vroom(self):
print("Vroom")

def details(self):
print("Manufacturer is:")
print(self.manufactuer)
print("Horsepower is:")
print(self.horsepower)

This seems more complicated than it is. First, we define the name of the class in the first line class Car:.

We initialize the class by giving it some properties using __init__ which takes any number of arguments. The first will be self, the next few are up to you and work just like function keyword arguments. Note that we also need to refer to those properties again by saying that these properties are part of the class itself (using self.property1 = property1 and so on). We can now use them in any other function we make up.

The next few functions or methods take only one argument self and thanks to our initialization, this carries all the other properties with it and allows us to call the properties by using self.property1 .

Now that our class is working, we can make an object using this class.

bmw_m5 = Car(manufacturer = "BMW", horsepower = 617)

One way to think about this is that we’re making a function using the class and assigning it to a variable. If you had no properties, this would be bmw_m5 = Car() .

We can then call its properties by using a period followed by the property name. We can also access methods in the class in the same way but adding brackets at the end.

print(bmw_m5.manufacturer)
bmw_m5.vroom()
bmw_m5.details()

Why do we add brackets for methods? If you remember, a method is a function and a function is called like this:

square_root(152)

When we use a period followed by the method name, we automatically pass the argument (in this case the object) to the method. So when we write bmw_m5.vroom() Python treats it like this vroom(bmw_m5). Although this won’t work, it’s helpful to think of methods like this.

Classes may seem complicated, but, at times, they’re extremely valuable. A lot of coders also use classes, so understanding what’s going on is invaluable when you’re looking up a solution online.

Useful Stuff

Comments

Comments are extremely useful when coding and you should constantly be writing comments when coding. I’ve avoided using comments in the past few parts, but in the subsequent ones, I’ll be using them regularly.

# This is a comment and is not real code. It's just here to help you
# Your comment is not run by Python. Anything to the right of a
# hash (#) on a line will not be run
print("Hello") # This is an inline comment# This is a
# Block comment
# It's used for
# Multiline comments
# It's common practice to avoid inline comments even though they
# do work. Also put a space
# after a hash
# Ideal comments should explain something clearly and take
# as much space as they need
# Asks for user name
user_name = input("User name please: )

Strings

You can write multiline strings, use numerical operators on strings, and insert variables inside strings.

# Triple quotes are used to make multiline strings
name = input('''What is your name?
Who are you?
Proclaim your name
''')
# You can add strings
full_name = "Sir/Madam " + name + " The First"
print(full_name)
# You can also multiply them
print((name + " ")*3)
# Use double or single quotes for normal strings but be consistent
# To put variable names inside put an f in front of the quotes and
# use curly brackets for the variable. Note that this can be done
# in many other ways.
print(f"Hello {name}! Good Morning!")

Efficiency

You won’t be graded on how fast your program runs (you’re not building for end-users) and how short the code is. So, write as many lines as you want and make it as easy to understand as possible so you can troubleshoot easily. Even for software engineers, efficiency is only an objective after creating a solution that works.

Naming

Use concise variable names that explain clearly what the variable contains. Avoid x y z number string value and other useless names, even though I used them gratuitously throughout the tutorial.

Your names should clearly define what sort of value the variable contains. This is also applicable to function names. It’s ok to write long names because when you come back to your code to fix something, you don’t want to be thinking about what s, t, u, p, i and d stand for.

It’s okay if all of this is causing some information overload. You’re not required to remember all the syntax at all times. A key programming skill is to Google effectively! At first, you’ll keep messing up syntax but pretty soon, you’ll have it in the back of your head. It’s also advisable to do some programming challenges daily to stay sharp. This not only helps your acclimatization to Python but also your problem-solving skills!

Some recommendations for great problem-solving sites: Hackerrank, Coderbyte, and Codewars. They all have great discussion panels to help you understand why your code didn’t work or to see if there are better solutions.

In the next part, we will learn how to install Python locally and run your code on your PC so you can make programs that work on your files.

--

--

Shuvo Saha
intelligentmachines

A business grad who spends way too much time on his computer. Currently a Marketing Analyst at Wise!