Interesting Python Tips and Tricks

Don’t worry if it doesn’t work right. If everything did, you’d be out of a job. (Mosher’s Law of Software Engineering)

Photo by Christina Morillo from Pexels


#1 Context Managers

The context managers allow to allocate and release resources precisely when a program wants to get access to a resource on the computer. It asks the OS for it and the OS provides it with a handle for that resource requested. Some common examples of such resources are files and network ports. Whenever we open a resource, we have to remember to close it, so that the resource is freed. But unfortunately, it’s easier said than done in the program. The with statement is a widely used example of context managers.

--------------------------------------------------------------
# Manually managing the resources
f = open('test.txt','r')
file = f.read()
f.close()
--------------------------------------------------------------
# Using with statement to manage the resources automatically with open('test.txt','r') as f:
   file = f.read()
--------------------------------------------------------------

This context managers can also be used in threads where we are manually acquiring and releasing locks, opening and closing the database connections manually so that the OS manages automatically for us.

#2 Underscores in Numeric Literals

Python’s syntax and number-from-string constructors so that underscores can be used as visual separators for digit grouping purposes in integral, floating-point, and complex number literals.

This is a common feature of other modern languages and can aid readability of long literals, or literals whose value should clearly separate into parts, such as bytes or words in hexadecimal notation.

# grouping decimal numbers by thousands
amount = 10_000_000.0

# grouping hexadecimal addresses by words
addr = 0xCAFE_F00D

# grouping bits into nibbles in a binary literal
flags = 0b_0011_1111_0100_1110

# same, for string conversions
flags = int('0b_1111_0000', 2)

#3 Unpack a tuple / list

In Python, elements of tuples and lists can be assigned to multiple variables. It is called sequence unpacking.

t = (0, 1, 2)

a, b, c = t

print(a)
print(b)
print(c)
# 0
# 1
# 2

l = [0, 1, 2]

a, b, c = l

print(a)
print(b)
print(c)
# 0
# 1
# 2

Because parentheses of tuples can be omitted, multiple values can be assigned to multiple variables in one line as follows.

a, b = 0, 1

print(a)
print(b)
# 0
# 1

#4 Unpack a nested tuple and list

We can also unpack a nested tuple and list. To expand the inner element, enclose the variable with () or [].

t = (0, 1, (2, 3, 4))

a, b, c = t

print(a)
print(b)
print(c)
# 0
# 1
# (2, 3, 4)

print(type(c))
# <class 'tuple'>

a, b, (c, d, e) = t

print(a)
print(b)
print(c)
print(d)
print(e)
# 0
# 1
# 2
# 3
# 4

#5 Unpack using _ (underscore)

By convention, unnecessary values may be assigned to underscores _ in Python. It does not have a grammatical special meaning but is simply assigned to a variable named _.

t = (0, 1, 2)

a, b, _ = t

print(a)
print(b)
print(_)
# 0
# 1
# 2

#6 Unpack using * (asterisk)

If the number of variables is less than the number of elements, adding an asterisk * to the variable name will assign the elements together as a list.

It is implemented in Python 3 and can not be used in Python 2.

The elements from the beginning and the end are assigned to variables without *, and the remaining elements are assigned as a list of variables with *.

t = (0, 1, 2, 3, 4)

a, b, *c = t

print(a)
print(b)
print(c)
# 0
# 1
# [2, 3, 4]

print(type(c))
# <class 'list'>

a, *b, c = t

print(a)
print(b)
print(c)
# 0
# [1, 2, 3]
# 4

*a, b, c = t

print(a)
print(b)
print(c)
# [0, 1, 2]
# 3
# 4

For example, when it is desired to assign only the first two elements of a tuple or a list to variables, the underscore _ may be used for unnecessary parts.

a, b, *_ = t

print(a)
print(b)
print(_)
# 0
# 1
# [2, 3, 4]

The same process can be written as:

a, b = t[0], t[1]

print(a)
print(b)
# 0
# 1

Note that even if there is only one element assigned to a variable with *, it is assigned as a list.

t = (0, 1, 2)

a, b, *c = t

print(a)
print(b)
print(c)
# 0
# 1
# [2]

print(type(c))
# <class 'list'>

If there are no extra elements, an empty list is assigned.

a, b, c, *d = t

print(a)
print(b)
print(c)
print(d)
# 0
# 1
# 2
# []

#7 Use enumerate() and zip() at the same time

In Python, enumerate() and zip() are useful when iterating elements such as lists in a for a loop. We can get the index with the enumerate() method, and get the elements of multiple lists together with zip() method.

If you want to get the elements of multiple lists and indexes, you can use enumerate() and zip() at the same time.

In this case, you need to enclose the elements of zip() in parentheses, like for i, (a, b, ...) in enumerate(zip( ... )).

names = ['Alice', 'Bob', 'Charlie']
ages = [24, 50, 18]

for i, (name, age) in enumerate(zip(names, ages)):
    print(i, name, age)
# 0 Alice 24
# 1 Bob 50
# 2 Charlie 18

We can also receive the elements of zip() as a tuple.

---------------------------------------------------------------
for i, t in enumerate(zip(names, ages)):
    print(i, t)
# 0 ('Alice', 24)
# 1 ('Bob', 50)
# 2 ('Charlie', 18)
---------------------------------------------------------------
for i, t in enumerate(zip(names, ages)):
    print(i, t[0], t[1])
# 0 Alice 24
# 1 Bob 50
# 2 Charlie 18
---------------------------------------------------------------

#8 Get quotient and remainder with divmod() method

We can calculate the quotient with // and the remainder with %.

q = 10 // 3
mod = 10 % 3
print(q, mod)
# 3 1

The built-in function divmod() is useful when you want both the quotient and the remainder. divmod(a, b) returns a tuple (a // b, a % b).

Each can be assigned to a variable using unpacking.

---------------------------------------------------------------
q, mod = divmod(10, 3)
print(q, mod)
# 3 1
---------------------------------------------------------------
answer = divmod(10, 3)
print(answer)
print(answer[0], answer[1])
# (3, 1)
# 3 1
---------------------------------------------------------------

#9 random.shuffle() shuffles the original list

The original list can be shuffled in place by using random.shuffle().


import random
l = list(range(5))
print(l)
# [0, 1, 2, 3, 4]

random.shuffle(l)
print(l)
# [4, 3, 2, 1, 0]

#10 random.sample() returns a new shuffled list

random.sample() returns a new shuffled list. The original list remains unchanged.

random.sample() returns random elements from a list. Pass the list to the first argument and the number of elements to return to the second argument. See the following post for details.

l = list(range(5))
print(l)
# [0, 1, 2, 3, 4]

lr = random.sample(l, len(l))
print(lr)
# [3, 2, 4, 1, 0]

print(l)
# [0, 1, 2, 3, 4]

#11 Shuffle strings and tuples

To shuffle strings or tuples, use random.sample() which creates a new object. random.sample() returns a list even when a string or tuple is specified to the first argument, so it is necessary to convert it to a string or tuple.

For strings, a list of characters is returned. Use the join() method to concatenate to a single string again.

sr = ''.join(random.sample(s, len(s)))
print(sr)
# caebd

For tuples, use tuple(), which creates a tuple from a list.

tr = tuple(random.sample(t, len(l)))
print(tr)
# (2, 1, 4, 3, 0)

#12 Set a seed

By giving an arbitrary integer to random.seed(), the seed for generating random numbers can be set.


random.seed(0)
l = list(range(5))
random.shuffle(l)
print(l)
# [2, 1, 0, 4, 3]


Source: medium.com

Recent Posts

See All

Tuning using HyperOpt in python

HyperOpt provides an optimization interface that accepts an evaluation function and parameter space, and can calculate the loss function value of a point in the parameter space. The user also specifie