Python Fundamentals in a Nutshell

Python Fundamentals in a Nutshell

A Brief Walkthrough

After some time off from Python, I decided to revisit some old concepts as well as learn a few new ones. Thought of summarizing them here:

  • If you are performing the same calculation within a function for different input arguments, use nested functions.

This nested function can take one input argument and return the value after the calculation is performed on that argument. In the main (outer) function, return this nested function with the different input arguments passed to it.

So your initial function definition:

def square_three_numbers(n1,n2,n3):
    sq_n1 = n1**2
    sq_n2 = n2**2
    sq_n3 = n3**2
    return (sq_n1,sq_n2,sq_n3)

Becomes:

def square_three_numbers(n1,n2,n3):
    def square_number(number):
        return (number**2)
    return (square_number(n1),square_number(n2),square_number(n3))

The second snippet is a way more efficient way of modularizing your code.

  • Use flexible arguments - '*args' and '**kwargs' when you don't know how many arguments you will be passing.

Use '*args' when you are just plainly passing the arguments. This gets passed into the function body as a tuple and then you can iterate through it to get your arguments.

def sum_numbers(*args):
    total=0
    for number in args:
        total=total+number
    return(total)

#Function call
print(sum_numbers(1,2,3))

#Output:
#6

Use '**kwargs' when you pass an identifier before your argument value. This gets passed into the function body as a dictionary and then you can iterate through it to get your arguments (with keys being the identifiers and values being the argument value).

#Function definition
def my_favourites(**kwargs):
    for key,value in kwargs.items():
        print("My favourite {0} is \'{1}\'!".format(key,value))



#Function call
my_favourites(series="Handmaid's Tale", movie="Rogue One: A Star Wars Story",song="Less I Know The Better")


#Output:
#My favourite series is 'Handmaid's Tale'!
#My favourite movie is 'Rogue One: A Star Wars Story'!
#My favourite song is 'Less I Know The Better'!

Is it weird that I took more time to decide my favourite movie than to write this code?

Notice the format() method for string. This is way easier than trying to concatenate strings using +.

  • Lambda functions (anonymous function) - Used usually when you want to pass a function as an argument to higher-order functions.
def exponent_function(exp):
    return lambda num : num ** exp

raised_to_10 = exponent_function(10)
raised_to_5 = exponent_function(5)

print(raised_to_10(2))
print(raised_to_5(2))

#Output:
#1024
#32

Lambda functions are used with:

map(function,sequence) - Applies the lambda function to all the elements in the sequence. Returns a map object.

numbers = [1,2,3,4]


#Use map() to apply the lambda function for all elements in your list
squares = map(lambda num:num**2, numbers)


#Remember, squares is a map object. So, convert it into a list to see what the values are!
print(list(squares))

#Output:
#[1,4,9,16]

filter(function,sequence) - Applies the lambda function with a condition to the elements in the sequence. Returns a filter object.

numbers = [1,2,3,4,5,6,7]


#Use the lambda function in filter to print even numbers from the list
even_numbers = filter(lambda nums:nums%2==0,numbers)


#Remember, even_numbers is a filter object. So, convert it into a list to see what the values are!
print(list(even_numbers))

#Output
#[2, 4, 6]

reduce(function,sequence) - Applies the lambda function to all the elements in the sequence. Returns a single value.

numbers = [1,2,3,4]


# Use reduce() to apply a lambda function over numbers
product = reduce(lambda item1,item2:item1*item2, numbers)


# Print the result
print(product)

#Output:
#24

The function is first applied to the first two elements. The result of this computation and the third value are again passed into the function and so on.

  • Iterators and Iterables - For efficient and flexible processing of data, especially when working with large datasets.

Iterables

fruits = ["apple", "banana", "orange"]
for fruit in fruits:
    print(fruit)

Output:

apple
banana
orange

In this example, the fruits list is an iterable object, and we can loop over its elements using a for loop.

Iterators

fruits = ["apple", "banana", "orange"]
fruit_iterator = iter(fruits)
print(next(fruit_iterator))
print(next(fruit_iterator))
print(next(fruit_iterator))

Output:

apple
banana
orange

In this example, we create an iterator object fruit_iterator using the iter() function. We then use the next() function to iterate over the elements of the fruits list. Each call to next() returns the next element in the list until there are no more elements to iterate over.

  • List Comprehensions - For loop reimagined.

When this code:

my_list=[]
for i in range(10):
    for j in range(5):
        my_list.append((j,i))
print(my_list)

becomes this:

my_list_comp=[(j,i) for i in range(10) for j in range(5) ]
print(my_list_comp)

Your program will send you a pop-up saying 'Thank you!'

Seriously. Try it.

However, to ensure that you stay pythonic, it is advisable to have a clear understanding of when to use list comprehensions and when not to.