Skip to main content

The missing guide to useful Python 3 features

Numerous people started to shift their Python version from 2 to 3 due to Python EOL. One of the most well-known changes is; print function in Python 2 is replaced by the print() function in Python 3. However, parentheses work in Python 2 if a space is added after print keyword because the interpreter evaluates it as an expression. Below, I introduce a few illustrations of amazing features you can find only in Python 3 in the hopes that it will solve your Python problems easily.

All examples are coded in python 3.8.0

f-strings (3.6 +)

It is hard to perform anything in whatever programming language without strings and you expect a structured way to work with strings to stay productive. Most people who use Python prefer to use the format method.

user = “Prince”
action = “coding”
log_message = ‘User {} has logged in and did an action {}.’.format(
user,
action
)
print(log_message)
# User Prince has logged in and did an action coding.

In addition to the format, Python 3 provides a versatile way of interpolating strings via f-strings. It looks like the same code as above using f-strings:

user = “Prince”
action = “coding”
log_message = f’User {user} has logged in and did an action {action}.’
print(log_message)
# User Prince has logged in and did an action coding.

Pathlib (3.4+)

f-strings are incredible, but strings such as file paths have their own libraries that make it easier to manipulate them. As a convenient abstraction for working with file paths, Python 3 provides pathlib. If you’re not sure why you should use pathlib, seek to read this excellent post by Trey Hunner — Why you should use pathlib.

from pathlib import Pathroot = Path(‘post_sub_folder’)
print(root)
# post_sub_folder
path = root / ‘happy_user’# Make the path absolute
print(path.resolve())
# /home/weenkus/Workspace/Projects/DataWhatNow- Codes/how_your_python3_should_look_like/post_sub_folder/happy_user

Type hinting (3.5+)

Static as against dynamic typing is a hot topic in software engineering and literally everybody has a perspective on it. I’ll let the reader decide when to write types, but I feel you should at least know that Python 3 supports type hints.

def sentence_has_animal(sentence: str) -> bool:
return “animal” in sentence
sentence_has_animal(“Donald had a farm without animals”)
# True

Enumerations (3.4+)

Python 3 facilitates a simple way to write enumerations in the Enum class. Enums are a useful way to encapsulate constants lists of constants so they do not appear randomly through the code without much structure.

from enum import Enum, auto
class Monster(Enum):
ZOMBIE = auto()
WARRIOR = auto()
BEAR = auto()
print(Monster.ZOMBIE)
# Monster.ZOMBIE

An enumeration is a set of symbolic names (members) bound to unique, constant values. Within an enumeration, the members can be compared by identity, and the enumeration itself can be iterated over. https://docs.python.org/3/library/enum.html

for monster in Monster:
print(monster)
# Monster.ZOMBIE
# Monster.WARRIOR
# Monster.BEAR

Built-in LRU cache (3.2+)

Almost in every horizontal slice of the software and hardware, we utilize today, caches are present. Python 3 makes it very simple to use by exposing an LRU(Least Recently Used) cache as a decorator called lru cache.

Below is a basic Fibonacci function that we understand will benefit from caching because with a recursion it does the same job several times.

import time
def fib(number: int) -> int:
if number == 0: return 0
if number == 1: return 1
return fib(number-1) + fib(number-2)start = time.time()
fib(40)
print(f’Duration: {time.time() — start}s’)
# Duration: 30.684099674224854s

Now we can use lru cache to configure it(this optimization technique called memoization). The runtime lowers from seconds to nanoseconds.

from functools import lru_cache
@lru_cache(maxsize=512)
def fib_memoization(number: int) -> int:
if number == 0: return 0
if number == 1: return 1
return fib_memoization(number-1) + fib_memoization(number-2)start = time.time()
fib_memoization(40)
print(f’Duration: {time.time() — start}s’)
# Duration: 6.866455078125e-05s

Extended iterable unpacking (3.0+)

I ‘m going to let code discuss here (docs).

 head, *body, tail = range(5)
print(head, body, tail)
# 0 [1, 2, 3] 4
py, filename, *cmds = “python3.7 script.py -n 5 -l 15”.split()
print(py)
print(filename)
print(cmds)
# python3.7
# script.py
# [‘-n’, ‘5’, ‘-l’, ‘15’]
first, _, third, *_ = range(10)
print(first, third)
# 0 2

Data classes (3.7+)

Python 3 provides data classes which have few restrictions and can be used to minimize boilerplate code since the decorator automatically generates special methods like ¼__init__( ) and __repr__( ). They are listed by the official proposal as ‘mutable named tuples with defaults.’

class Armor:
  def __init__(self, armor: float, description: str, level: int = 1):
self.armor = armor
self.level = level
self.description = description
  def power(self) -> float:
return self.armor * self.level
armor = Armor(5.2, “Common armor.”, 2)
armor.power()
# 10.4
print(armor)
# <__main__.Armor object at 0x7fc4800e2cf8>

The same implementation of Armor using data classes.

from dataclasses import dataclass
@dataclass
class Armor:
armor: float
description: str
level: int = 1
   def power(self) -> float:
return self.armor * self.level
armor = Armor(5.2, “Common armor.”, 2)
armor.power()
# 10.4
 print(armor)
# Armor(armor=5.2, description=’Common armor.’, level=2)

Implicit namespace packages (3.3+)

One way to structure Python code is in packages (folders with an __init__.py file). The following example is provided by Python’s official documentation.

sound/                   Top-level package 
__init__.py Initialize the sound package
formats/ Subpackage for file format conversions
__init__.py
wavread.py
wavwrite.py
aiffread.py
aiffwrite.py
auread.py
auwrite.py
effects/ Subpackage for sound effects__init__.py
echo.py
surround.py
reverse.py
filters/ Subpackage for filters__init__.py
equalizer.py
vocoder.py
karaoke.py

In Python 2, every folder above had to have an __init__.py file which turned that folder into a Python package. In Python 3 these files are no longer needed once Implicit Namespace Packages are introduced.

sound/                      Top-level package 
__init__.py Initialize the sound package
formats/ Subpackage for file format conversions
wavread.py
wavwrite.py
aiffread.py
aiffwrite.py
auread.py
auwrite.py
effects/ Subpackage for sound effectsecho.py
surround.py
reverse.py
filters/ Subpackage for filtersequalizer.py
vocoder.py
karaoke.py

Note: If you find, it is not as simple as I pointed it out in this section, from the official PEP 420 Specification — __init__.py is still required for regular packages, dropping it from the folder structure will turn it into a native namespace package which comes with additional restrictions, the official docs on native namespace packages show a great example of this, as well as naming all the restrictions.

Underscores in numeric literals (3.6+)

Python 3.6 provides an excellent way to allow reading numerical literals by enabling underscored in the numbers. This can be used to demonstrate, for instance: thousands, hexadecimal and binary numbers.

cost = 10_000
print(f’Cost: {cost}’)
# Cost: 10000
hex_flag = 0xDAFE_FFF8
print(f’Hex flag: {hex_flag}’)
# Hex flag: 3674144760
binary = 0b_0011_1001
print(f’Binary: {binary}’)
# Binary: 57

Python 3.6 provides an excellent way to allow reading numerical literals by enabling the numbers to be underscored. This can be used to demonstrate, for instance: thousands, hexadecimal and binary numbers.

Assignment expressions — “walrus operator” (3.8+)

With Python’s latest version, the walrus operator is introduced, which makes a variable assignment of expression. It can be useful if you intend to refer to the expression later in code and save a line or two in code.

animals = [‘dog’, ‘lion’, ‘bear’, ‘tiger’]for animal in animals:
if (len_animal := len(animal)) > 4:
print(f’The animal “{animal}” has “{len_animal}”, letters!’)
# The animal “tiger” has “5”, letters!

The Ending Note

As almost every internet list, this one is not complete. I hope this information illustrates you at least one Python 3 functionality that wasn’t known previously, and it will allow you to write smoother and more instinctive code.

Comments

Popular posts from this blog

Capture and compare stdout in python unit tests

A recent fan of TDD, I set out to write tests for whatever comes my way. And there was one feature where the code would print messages to the console. Now - I had tests written for the API but I could not get my head around ways to capture these messages in my unittests.
After some searching and some stroke of genius, here's how I accomplished capturing stdout.


The economics of crypto investing

If you believe in the greater fool theory, there is no other market as speculative and volatile as the crypto market today. We are perhaps living in the biggest bubble of our times. I am not bullish on this market in particular. I am bullish on the mania. 90% of the cryptos we see today will crash. They are just tokens with no tangible value generation capability. However, I believe that the mania and euphoria will stay.

Having said that, should one consider investing in this market? Certainly!
The risk/reward is lovely, potential upsides and margins are huge and with 3-5% of your net worth, the bet on the mania is worth it.

How does one choose where to invest?

If you follow the stock markets, you are expected to do thorough Fundamental Analysis before investing. Expect the same for the crypto market. I invest in large caps. I invest in index funds. And I invest over and over again. Markets rise, always. Extrapolating the same strategy - invest in indices - the top 10 tokens by perfo…

On working remote

The last company I worked for, did have an office space, but the code was all on Github, infra on AWS, we tracked issues over Asana and more or less each person had at least one project they could call "their own" (I had a bunch of them ;-)). This worked pretty well. And it gave me a feeling that working remote would not be very different from this.

So when we started working on our own startup, we started with working from our homes. It looked great at first. I could now spend more time with Mom and could work at leisure. However, it is not as good as it looks like. At times it just feels you are busy without business, that you had been working, yet didn't achieve much. If you are evaluating working from home and are not sure of how to start, or you already do (then please review and add your views in comments) and feel like you were better off in the office, do read on. Remote work is great. But a physical office is better. So if you can, find yourself a co-working sp…