Python - Handy, and Kool stuff

Stuff to be on Finger-tips

Python is the Atoms and Molecules of your AI journey. You will never realize this explicitly but you will use it every moment and in every line of your code. Having a quick hand on Python enables you to test new concepts quickly which eventually encourages you to try new ideas on the ground.

In this blog, we will learn many of the important Python stuff that might be new to you Or you must keep it at your fingertips.

1. For loop and List comprehension analogy

List comprehension is the go-to way to iterate in Python, you should seldom use for-Loop. Here, we will try to develop an analogy of list-comprehension with for-loop (because that syntax is the default in our mind)

With the for-loop analogy, you can apply the list comprehension to a deeper level of nesting. Check the Image i.e. how the numeric indicator is mapped between for-loop and list-comprehension

list_comprehension_blog.png

simple_list = ['This', 'is', '10xAI', 'Learning', '!!!']

# ---> [<<<Your expression>>> for elem in simple_list]

[elem.upper() for elem in simple_list]

Output
['THIS', 'IS', '10XAI', 'LEARNING', '!!!']

2. Nested List Comprehension

With the analogy, now it is a cakewalk.

nested_list = [ ['This', 'is'], ['10xAI', 'Learning'], ['It\'s', 'all'], ['about','AI'], ['!','!'] ]

# ---> [<<<Your expression>>> for inner_list in outer_list for elem in inner_list]

[elem for inner_list in nested_list for elem in inner_list]

Output
['This', 'is', '10xAI', 'Learning', "It's", 'all', 'about', 'AI', '!', '!']

3. zip and enumerate

Zip is a handy tool to pack the respective elements of two sequences. Enumerate doesn't need any introduction. So, just placing a simple example

models = ['LR', 'RandomForest', 'DecisionTree', 'SVM', 'KNN']
score = [0.7, 0.9, 0.8, 0.75, 0.72]

# Zipping respective pair
[[tup[0],tup[1]] for tup in zip(models,score)]

# Enumerate with Dict-Comprehension

{id:{tup[0]:tup[1]} for id,tup in enumerate(zip(models,score))}

4. Passing function as parm

Functions are objects too. You can assign and pass them as any other type using its Identifier.

def g(x) : return 10*x
def f(g_x, x): return 1/g_x(x) # Accepts functin as one of the parameters

simple_list = [0.1, 0.2, 0.4, 0.5, 1]

[f(g , i) for i in simple_list] # Passing function as argument

# Can assign another identifier
func_var = g  # No parenthesis
[f(func_var , i) for i in simple_list]

Output
[1.0, 0.5, 0.25, 0.2, 0.1]

5. print "sep" and "end" parameters

Know and use these two parameters for the print function.

print(objects, sep=' ', end='\n', file=sys.stdout, flush=False)

end defines what will be appended at the end of a print statement. Default is a new line, that' why the next print starts from the next line. sep defines how two objects will be separated. Default is blank.

You can change both these defaults.

models = ['LR', 'RandomForest', 'DecisionTree', 'SVM', 'KNN']
score = [0.7, 0.9, 0.8, 0.75, 0.72]

# Defaults
for i in range(5):
    print(models[i], score[i])

# using sep
for i in range(5):
    print(models[i], score[i], sep="==")

# using end
for i in range(5):
    print(models[i], score[i], sep="=", end=" | ")

Output
LR=0.7 | RandomForest=0.9 | DecisionTree=0.8 | SVM=0.75 | KNN=0.72 |

6. Throw-away variable unpacking with *

The packing and unpacking of variable are one of the kool stuff in Python. Let's quickly learn some of its variations and extension. Using a * in the right you can ignore the items which are not required.

many_vars = [100, "aqz", 0.002, "ignore"]

# We just need the 100
var, *_ = many_vars # _ is the throw-away variable
print(var)

# If we want to keep all others just for future ref
var, *my_bin = many_vars
print(my_bin)  # my_bin is a list

7. Nested sequence unpacking with *

With an * before a sequence will unpack it.

many_vars = [ [100, "aqz"] , [0.002, "ignore"] ]

# Default way, we need the 100
var, *my_bin = many_vars
print(var)  # var is the list as due to only 1st level unpacking

# Using *, we need the 100
var, *my_bin = (*many_vars[0],*many_vars[1])
print(var)  # var is the list as due to only 1st level unpacking

8. Using set, sorted, reversed

Whenever you need to get the unique values in a sorted manner. Use this

text = "a quick brown fox jumps over the lazy dog" 

sorted(set(text))
# Use join for making it String
'_'.join(sorted(set(text)))

# Reversed it 
list(reversed(sorted(set(text)))) # Reverse returns an Iterator, so list func applied

Output
'_a_b_c_d_e_f_g_h_i_j_k_l_m_n_o_p_q_r_s_t_u_v_w_x_y_z'

9. Slicing with negative Index and step

First thing first - Python is 0-indexed.

Slice has 3 elements i.e. start, stop, step. The last item is indexed as -1 and the second last is indexed as -2 and son on. The step can be negative. The last index gets excluded.

Let's apply this information.

simple_list = [1, 7, 8, 0, 5, 23]

# with negative Index
simple_list[:-2 ] # From start to second-last element(-2 excluded)

# Trimming
simple_list[1:-1 ] # Very often needed with String

# Alternate Even-Indexed
simple_list[::2 ] 

# Alternate Odd-Indexed
simple_list[1::2 ] 

# Reversing the list
simple_list[::-1 ] # One of the coolest Python stuff

10. Adding power with ".join"

Join is your friend when you want to get the string from a sequence by concatenating all its elements with a specific character. You can also concatenate with blank.

simple_list = ['This', 'is', '10xAI', 'Learning', '!!!']

' '.join(simple_list)

# With List-comprehension
' '.join([elem.upper() for elem in simple_list])

Output
THIS IS 10XAI LEARNING !!!

11. map with multiple sequences

The map is another very useful built-in function. It takes a function and one or more Iterable and applies the function to the elements of the Iterable. Function argument will be a tuple having a number of elements equal to the number of Iterable

simple_list = [1, 2, 3, 4, 5 ]
def func(x) : return x**2 

# Get the square
list(map(func, simple_list)) # Will return an Iterator, so use list 

# Use different exponent for different values
exponent_list = [5, 4, 3, 2, 1 ]

def func(x, y) : return x**y 

list(map(func, simple_list,exponent_list)) # passing two list, hence function should accept 2 parameters

12. Apply filter on sequence

The filter is another very handy built-in function. It takes a function and an Iterable and return the elements of the Iterable for which the function evaluates to True

simple_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
def odd(x) : return True if x%2!=0 else False 

# Get the Odd elements
list(filter(odd, simple_list)) # Will return an Iterator, so use list 

# This is the same as this :-)
[elem for elem in simple_list if elem%2!=0]

13. Permutation, Combination with Itertools

Itertools is a handy module in Python when you quickly want to generate a permutation, a combination of product of two sequences.

import itertools

comb = itertools.combinations([1,2,3,4], 3) # all combination(i.e. 2,3 and 3,2 are same ) of length 3
list(comb)

perm = itertools.permutations([1,2,3,4], 3) # all permutation (i.e. 2,3 and 3,2 are different ) of length 3
list(perm)

prod = itertools.product(['A','B'],[1,2,3,4]) # all Cartesian product
list(prod)

14. Generator expression

We can use a Generator Expression i.e. genexps as a simple way to write an inline generator.

It’s work exactly like List Comprehension except,

  • Uses ( ) instead of [ ]
  • Does not generate a List but an iterator yielding one item at a time i.e. saves memory
  • Use it when you want to pass an Iterator but not intended to save
gen = (x*x for x in range(10))
next(gen) #0
next(gen) #1
next(gen) #2

list(gen) # Make a list

# Just like List Comprehension without saving a List in memory
sum(x*x for x in range(10)) # Don’t need the extra Brackets when used with a function

15. Iterable/Iterator

This is quite confusing sometimes. Though you may sail through w/o understanding these concepts. Something is Iterable means we can loop over its elements This is the collection we use in for loop i.e. for elem in Iterable:

An Iterator is more of the background implementation to make the loop happening

Technically -

Iterable, when called on iter() built-In function return an Iterator Iterator has a next method that returns the next element and moves the position to the new next.

s = 'cat'
t = iter(s)  # Made an Iterator
next(t)      # call the next built-in function
# Output 'c'
next(t)        
# Output 'a'

Read this Answer at SO
stackoverflow.com/a/9884501/2187625

No Comments Yet