Python Comprehensive Walkthrough with extensive examples

Introduction

Python is one of the popular and general programming languages which is used in every domain.

Let's do a walkthrough on all the important aspects of this language, focusing more on the code snippets.

Compiler

Converting high-level language (Python code) to low-level language (Byte-code). One of the main advantages it does is syntax checks.

Variables

Python is a dynamic-typed language, so we can change the type of variable at a given point. For example:-

def main():
    x = 20
    print("First :", x)
    x = "Twenty two"
    print("Second :", x)
    is_check = False
    is_none = None

main()
"""
Output
First: 20
Second: Twenty two
"""

Some advanced data structures are as follows List | Set | Dict | Tuples.

  • List, Sets and Dict are mutatable data-structure.
lst = [1, 2, 3, 5, 8]
unqiue_set = {2, 3, 2, 4}
new_dict = {"first": 1}
tu = (1, 2, 3)

Conditional statement

The main conditional keywords are if, elif and else.

def main():
    x = 10
    y = 20
    z = "check"
    if x and y or not y and x:
        print("First")
    elif c in z:
        print("Second")
    else:
        print("Third")

Looping

Here we are using range function which would start from 0 to 4 in the below example.

def main():
    count = 0
    for i in range(0, 5):
        count += 1
        print(i)
    while count < 10:
        print(count)
        count += 1

List Comprehension

lst = [i for i in range(1, 11) if i % 2 == 0]

Exceptions

def main():
  try:
    a = 10 / 0
  except Exception as  e:
    print("Exception due to various logging: ", e)
  finally:
    print("Completion")
main()

Scope

x = 1
def main():
  x = 0
  print(x) # 0

main()
print(x) # 1
value = 0

def main():
  # this is bad practice!!!
  # asking compiler update value in the global level, 
  # basically this is best example of side-effect
  global value
  value = 5

print(value) # 0
main()
print(value) # 5

Sorting

lst = [2, 3,10, 5]
list.sort(reverse=True) # mutate the original list
sorted(list, reverse=True) # return sorted list

Modules and Packages

__name__ is a special variable that provides the current execution file like "__main__". The imported modules are not considered as main, only the one which is the entry point of execution.

# functions.py
def foo():
    print("Foo")

# main.py
import functions as f
# OR `from functions import foo`
# OR `from functions import *` -> to access everything from the file, bad
# practice.
if __name__ == "__main__":
    f.foo()
# code/__init__.py -> This file make it a package
print("Init")
# code/abc.py 
print("ABC")
# code/def.py
print("DEF")

# main.py
import code.abc # this will print the Initi and then ABC once
if __name__ == "__main__":
    print("main")
# code/__init__.py
import code.abc
import code.def
# code/abc.py 
print("ABC")
# code/def.py
print("DEF")

# main.py
import code # prints both ABC and DEF once.
  • If the file is in the same package we can use from . import abc .

File

file = open("file.txt", "r") # reading mode
print(file.read())
file.close() # close the file always to keep memory leak
# OR
# context-manager `with`, it automatically close it.
with open("file.txt", "r") as file:
    print(file.read())
    readLine = file.readline() # create list of string spliting buy new-line
    print(readLine)
    print(readLine[0].strip()) # strip removes white-space and \n

when using w mode or known as write mode allows writing data in the file, One key thing to remember is when using this mode if the already exists then it would be overridden by the code.

a append mode adds the file cursor at the very last line of the file, and doesn't override. r+ mode reads + write. Using file.seek(0) moves the cursor to the beginning of the file.

Argument and Keyword arguments

Python provides a special operator to unlock unlimited arguments passing to a function.

def tail(*args, **kwargs):
    print(args, kwargs)

tail([1, 2, 3], {"k": 2, "b": 3})

Lambda Functions

Inline functions or Arrow functions (coming from JS world), are used mostly with map or filter methods.

func = lambda x, y, z=0: x + y + z
print(func(1, 2))

lst = [1, 2, 3, 4, 5]
new_lst = map(lambda x: x**2, lst)
print(list(new_list))

filter_lst = filter(lambda y: y % 2 == 0, list)

Function closures

The function can be passed as an argument in another function (First call function).

def foo(x):
   return x ** 2

def boo(func, y):
    result = func(y)
    return result

print(boo(foo, 12))

Iterator

Everything that can be looped over is iterators, like list .

x = [1, 2, 3]
x_iter = iter(x) # or x.__iter__() are the same things
print(next(x_iter)) # 1 or we can use like x_iter.__next__()
print(next(x_iter)) # 2
print(next(x_iter)) # 3

Creating custom iterators

class Numbers:
    def __init__(self, num, num2, num3):
        self.num = num
        self.num2 = num2
        self.num3 = num3

    def __iter__(self):
        return NumberIterator(self.num, self.num2, self.num3)

class NumberIterator:
    def __init__(self, one, two, three):
        self.one = one
        self.two = two
        self.three = three
        self.current = 0

    def __next__(self):
        self.current += 1
        if self.current == 1:
            return self.one
        elif self.current == 2:
            return self.two
        elif self.current == 3:
            return self.three
        else:
            raise StopIteration

nums = Numbers(1,2, 3)

for val in nums:
    print(value)

Generator

Same as the Iterator. Used in modern programming, iterators are more legacy ways of doing things.

def gen():
    yield 1
    yield 2
    yield 3
itr = gen() # Generator object
next(itr) # 1
next(itr) # 2
next(itr) # 3

for i in itr:
    print(i)

"""
Why this is optimal then regular fib, because in that case would have be required
to store it in the list which would keep track of all the data, while 
in this way we are just concerned with last value.
"""
def fib(n):
    last = 1
    second_last = 1
    current = 3
    while current <= n:
        num = last + second_last
        yield num

        second_last = last
        last = num
        current += 1

for i in fib(10):
    print(i)

Threads and Processes

Process: This is just a program that is executed by the operating system.

Thread: It is what makes of process, it's part of the process, multiple threads make a process.

For example, if you have 6 cores then 6 processes or instructions can run at the same time in parallel.

There is a new tech called Hyper-threading, which is logical core and physical core. One physical core is broken into multiple logical cores which means every logical core is capable of executing instructions at the same time.

Global interpreter Lock

At a time only one thread would be using the interpreter, everything else would be locked. This is specific to Python, that's why you cannot have parallelism in Python. Lock <=> Mutex.

from threading import Thread, Lock
from time import sleep


def run(log_str, lock: Lock):
  lock.acquire() # waiting mode
  sleep(1)
  print(log_str)
  lock.release() # released mode

lock = Lock() # thread2 won't be executed until acquire is not released
thread1 = Thread(target=run, args=("run 1", lock))
thread2 = Thread(target=run, args=("run 2", lock))

# Execute the thread callback
thread1.start()
thread2.start()

Asynchronous Execution

From the later version of the python, we have the introduction of async in the language which provides a single-threaded concurrency approach to execution.

import asyncio

async def population():
    await asyncio.sleep(1)
    print("population")

async def main():
    print("main") #1
    await asyncio.sleep(2) #2 await is required in case of async
    task = asyncio.create_task(population()) # will continue with next line of code
    print("main end") #3
    await task #4 wait until async is not completed

# this function is required in order to start the async entry point
asyncio.run(main())

Conclusion

As we conclude, may these insights foster a deeper appreciation for Python's capabilities, propelling developers into a world where their imaginations become the blueprint for innovation.