Recently, I attended a Python programming bootcamp organized by MathSPP blogger Rodrigo Girao Serrao. This Bootcamp uses the Code Advent of Code platform, a cool programming event that takes place every year from December 1 to 25. Each day, the site releases two new puzzles for everyone to solve.

Overall, it was a good learning experience. I learned a lot of tips not only from the organizers, but also from the other camp participants. There was an emphasis on making the most of Python’s built-in functions and modules, as well as writing clean and elegant code.

This article is both my way of documenting these new techniques I’ve learned and my effort to share them with you. They have helped me greatly improve my Python programming skills, and I hope they will help you in the same way. Are you ready? Let’s get right in!

directory

  1. undervaluedenumerate()
  2. int()Functions are more useful than you think
  3. Let us assert:assertStatement!
  4. Unpack and pack*The power of operators
  5. Retrieve a value from a dictionary? use.get()And abandon[]!
  6. defaultdict– Create dictionaries with default values
  7. Sort it any way you wantsorted

1. Underratedenumerate()

It is quite common to iterate over iterable objects, such as lists, primitives, or strings. Some of us might do things like this.

>>> lst = ["a", "b", "c", "d"]>>> for idx in range(len(lst)):...     print(f"Index: {idx} --> Element: {lst[idx]}")
Copy the code

If we were simply going through the list, it would be redundant to calculate its length range. Instead, use enumerate(), which is a built-in function for just that purpose. The enumerate() function returns an enumeration object that holds the index and element pairs of an iterable.

>>> enumerate(lst)<enumerate at 0x1dde1211e80>
Copy the code

If you wrap it in list(), you can see these pairs.

>>> list(enumerate(lst))[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]
Copy the code

With enumerate(), the previous code can be rewritten as.

>>> lst = ["a", "b", "c", "d"]>>> for idx, item in enumerate(lst):...     print(f"Index: {idx} --> Element: {item}")
Copy the code

Suppose you want the starting index to be 1, not 0. You can specify this with the optional start argument.

>>> lst = ["a", "b", "c", "d"]>>> for idx, item in enumerate(lst, start=1):...     print(f"Index: {idx} --> Element: {item}")
Copy the code

2. The int() function is more useful than you think

You’ve probably used int() to convert a string or a floating point number to an integer.

# Converting a string into an integer>>> var = "5">>> print(int(var))>>> print(type(int(var)))
Copy the code

For a string, it must be a string representation of a valid integer, or an error will be raised.

# Converting a string into an INTEGER >>> var = "5.4321">>> Print (int(var))>>> Print (type(int(var))))Copy the code

Interestingly, the int() function allows whitespace when converting an integer represented by a string to an integer.

>>> int("5\n") == int("   5  ") == int("\t\n 5 \n\t ") == 5
Copy the code

For floating-point numbers, int() truncates the decimal point.

# Converting a float into an INTEGER >>> var = 5.4321>>> print(int(var))>>> print(type(int(var))))Copy the code

In addition to strings and floating point numbers, did you know that int() can also be used to parse binary numbers into integers? We just need to specify the base=2 argument.

# Converting binary numbers into an integer>>> print(int("1000", base=2))>>> print(int("111110100", base=2))
Copy the code

3. Let’s assert that assertion statement!

The assert statement is a Boolean expression that checks if a condition is true. The condition follows the assert keyword. If the condition is true, nothing happens and the program moves on to the next line of code.

>>> x = "Hello, World!" >>> assert x == "Hello, World!" >>> print(x)Copy the code

However, if the condition is false, the code stops and an error is triggered.

>>> x = "Hello, World!" >>> assert x == "Hi, World!" >>> print(x)Copy the code

You can also specify a custom error message after the condition.

>>> x = "Hello, World!" >>> assert x == "Hi, World!" , "Uh oh, the condition is not met!" >>> print(x)Copy the code

So, the general syntax looks like this.

assert <insert condition>, <insert optional error message>
Copy the code

Because programs stop when conditions are not met, assert statements are a great debugging tool — to see what parts of your code are failing, and why? For example, you can use it to check data types or specific input values coming into a function, or to check the output value of a function given some fixed input.

4. Decompress and pack — the power of the * operator

Decompression and packaging are useful and convenient features in Python. You can unpack values stored in iterators, such as primitives, strings, and lists to the right of the assignment operator, and assign them to variables to the left of the assignment operator. These variables will be assigned according to their relative positions in the iterative representation.

# Unpacking a tuple>>> a, b, c = (1, 2, 3)>>> print(a)>>> print(b)>>> print(c)
Copy the code

Packaging, on the other hand, uses the * operator, which allows you to package multiple values in a single variable.

# Packing with a tuple>>> a, *b = (1, 2, 3)>>> print(a)>>> print(b)
Copy the code

In addition to primitives, lists, and strings, packaging and unpacking can also be applied to generator objects, collections, and dictionaries. This is a handy tool when you want to swap values between variables or perform multiple assignments simultaneously. It makes your code more readable.

# Swapping values between variables>>> a = 1>>> b = 2>>> a, b = b, a>>> print(a)>>> print(b)
Copy the code

If you’re interested in learning more, here’s an article on packaging and unpacking that explains it quite clearly.

5. Retrieve values from dictionaries? Use.get() and ditch []!

Suppose you have a dictionary that maps a key to its corresponding value. In the following example, to retrieve the English word for a key in the NUM_to_words dictionary, you might want to use square brackets.

>>> num_to_words = {1: 'one', 2: 'two', 3: 'three'}>>> print(num_to_words[2])
Copy the code

What if you want to retrieve English words for keys that don’t exist in the NUM_to_words dictionary? Yes, you guessed it — it caused an error!

>>> num_to_words = {1: 'one', 2: 'two', 3: 'three'}>>> print(num_to_words[4])
Copy the code

The.get() method would be a more robust and practical choice than square brackets. The.get() method returns the value of the key that exists in the dictionary, no different from using square brackets.

>>> num_to_words = {1: 'one', 2: 'two', 3: 'three'}>>> print(num_to_words.get(2))
Copy the code

The benefits of.get() are now apparent when querying the value of a nonexistent key in the dictionary. Instead of raising KeyError and breaking your code, it defaults to returning a value of None and keeps your code running.

>>> num_to_words = {1: 'one', 2: 'two', 3: 'three'}>>> print(num_to_words.get(4))
Copy the code

The nice thing about.get() is that you can even specify a custom value to return if the key is not found.

>>> num_to_words = {1: 'one', 2: 'two', 3: 'three'}>>> print(num_to_words.get(4, "Uh oh... key is not found!" ))Copy the code

One use case of.get() is useful when replacing a value in a list with the corresponding value in a dictionary. In the following example, we want to replace each element in num_list with its corresponding English word using the num_to_words dictionary. If square brackets are used, the code breaks because 4 is not in the dictionary key.

# Using square brackets>>> num_to_words = {1: 'one', 2: 'two', 3: 'three'}>>> num_list = [1, 2, 3, 4, 5, 6]>>> word_list = [num_to_words[num] for num in num_list]>>> print(word_list)
Copy the code

However, if we use the.get() method instead, the code will work.

# Using .get() method with default value of None>>> num_to_words = {1: 'one', 2: 'two', 3: 'three'}>>> num_list = [1, 2, 3, 4, 5, 6]>>> word_list = [num_to_words.get(num) for num in num_list]>>> print(word_list)
Copy the code

Perhaps.get() returns None for nonexistent keys, which is still not ideal. We can specify the second argument to the.get() method so that it will return the key itself if it is not found in the num_to_words dictionary.

# Using .get() method with customised default value>>> num_to_words = {1: 'one', 2: 'two', 3: 'three'}>>> num_list = [1, 2, 3, 4, 5, 6]>>> word_list = [num_to_words.get(num, num) for num in num_list]>>> print(word_list)
Copy the code

6. Defaultdict – Creates a dictionary with default values

Another way to avoid keyerrors from querying for keys that don’t exist in the dictionary is to use Defaultdict in the built-in Collections module.

Using Defaultdict, you can specify a “default value factory” that returns the desired default value for any non-existent key. Here, we use a lambda function to do this when initializing a DefaultDict object.

>>> num_to_words_dd = defaultdict(lambda: "Uh oh... key is not found in `defaultdict`!" )>>> num_to_words_dd[1] = 'one'>>> num_to_words_dd[2] = 'two'>>> num_to_words_dd[3] = 'three'>>> print(num_to_words_dd)Copy the code

When querying for keys that exist in a DefaultDict object, it is no different than a normal dictionary object. To illustrate how Defaultdict works, the code snippet below uses square brackets instead of the.get() method.

>>> num_to_words_dd[2]
Copy the code

However, if you query for a non-existent key, the default value will be returned.

>>> num_to_words_dd[5]
Copy the code

You can also initialize a Defaultdict with an int or list keyword. If you initialize it with an int, a Defaultdict object is created with a default value of 0. When you query for a key that doesn’t exist, it returns 0.

>>> counter = defaultdict(int)>>> lst = [0, 1, 2, 2, 3, 1, 1, 0]>>> for num in lst:...     counter[num] += 1>>> print(counter[0]) # Key that exists>>> print(counter[5]) # Key that does not exist
Copy the code

Similarly, if you initialize it with a list, a DefaultDict object is created with a default value of an empty list, and a query for a nonexistent key returns [].

>>> country_list = [('AU','Australia'), ('CN','China'), ...                 ('FR','France'), ('SG', 'Singapore'), ...                 ('US', 'United States'), ('PT', 'Portugal')]>>> country_dict = defaultdict(list)>>> for code, country in country_list:...     country_dict[code].append(country)>>> print(country_dict['AU']) # Key that exists>>> print(country_dict['BX']) # Key that does not exist
Copy the code

All in all, defaultDict is a good choice if you need to create a dictionary and have some default value for each element.

7. Usesorted() sort in any way

If you want to sort something iterable, such as a list, a string, or a tuple, you can use the sorted() function. It returns a list with the order of the original elements, without changing the original sequence.

For strings, it returns a list of characters, preceded by punctuation or space, followed alphabetically by uppercase and lowercase letters.

>>> sorted("Hello, World!" )Copy the code

For a list of numbers, it returns a sequence sorted in ascending order.

>>> sorted([5, 2, 4, 1, 3])
Copy the code

For a list of strings, it returns an alphabetical sequence based on the first character.

>>> fruits = ["apple", "watermelon", "pear", ...           "banana", "grapes", "rockmelon"]>>> sorted(fruits)
Copy the code

You can also reverse this sequence by specifying reverse to True in the sorted() function.

>>> sorted(fruits, reverse=True)
Copy the code

Did you also know that you can customize how you want iterators to be sorted? You can specify a function and assign it to the key argument in the sorted function. For example, if you want to sort the fruits list in ascending order by the length of each word, you can do so.

>>> sorted(fruits, key=len)
Copy the code

Or, if you want to sort the fruit by the number of letters “n “in each word, you can specify a lambda function like this.

>>> sorted(fruits, key=lambda x: x.count('n'))
Copy the code

We can also sort by referring to another iterator. In the following example, we sort the fruits by increasing price according to the prices dictionary.

> > > prices = {" apple ": 1.4," watermelon ": 4," pear ": 1.2,... >>> sorted(fruits, key=lambda x: prices.get(x))Copy the code

All right! That’s it for now. Thank you for making it this far. I hope you’ve learned the simple tricks of writing elegant code and made the most of Python’s lesser-known built-in functions and modules.

I’ve only scratched the surface of some of these techniques; They can be written as a single article. Therefore, I strongly encourage you to check out more related resources to learn more.

The resources

  1. Python Problem Solving Boot Camp 2021, Rodrigo Girao Serrao
  2. Enumerate Me, Pydon’t, April 6, 2021, Rodrigo Girao Serrao
  3. Unpacking in Python. Beyond Parallel Assignment, 19 September 2021, Leodanis Pozo Ramos
Want to Connect?
Copy the code