You know Python! Or at least, you think you do. Even though I think I do, and even after eight years of full-time experience, I continue to learn new things. I suppose that’s the remarkable aspect of programming: you never cease to learn.
I’ve worked with data scientists, data engineers, and software engineers of all levels. Some had vast knowledge from which I could continue to learn, while others had some catching up to do.
I have tried to gather and discuss some of the most obscure yet useful functionalities here. I aim to omit basic knowledge, which you could probably just read in the Python tutorial, and focus on more advanced concepts.
Prepare to impress your colleagues and friends with the knowledge you are about to gain.
Enumerations
We have to use these more often. At least, it is one to have in your toolkit. I will give you a small example: let’s say you have a dataclass Car and you would like to have a field that tells you the brand, you would probably want to use Enums for this one. Why? Take a look at the following example:
from dataclasses import dataclass
from enum import Enum, unique
@unique
class CarBrand(Enum):
VOLVO = "volvo"
BMW = "bmw"
VW = "volkswagen"
@dataclass
class Car:
brand: CarBrand
volvo = Car(brand="volvo")
First, let’s break down a little bit of the code:
– Enum This class ensures the members are unique, so you can’t use VOLVO twice with a different value.
– @unique The unique decorator makes sure the values are unique as well. So, you cannot have two members (e.g., VOLVO and BMW) with the same value.
Now, the above code won’t throw an error when using the Python interpreter because Python does not support static typing, and type hints are… hints. But it will throw an error when you use, for example, Mypy, which is definitely worth looking at. Combining enumerations and Mypy will produce more predictable, readable, and less error-prone code. Here’s an example:
$ mypy enumerations.py
enumerations.py:17: error: Argument "brand" to "Car" has incompatible type "str"; expected "CarBrand" [arg-type]
Found 1 error in 1 file (checked 1 source file)
Mixin
A Mixin is a special kind of multiple inheritance. If you want to provide optional features for a class or use one particular feature in many different classes, you would probably like to use Mixins.
I have a special example below:
from enum import Enum, unique
@unique
class CarBrand(str, Enum):
VOLVO = "volvo"
BMW = "bmw"
VW = "volkswagen"
message = "I drive a " + CarBrand.VOLVO
print(message)
So, Enum does not contain the special __add__ method, but str does. So, if we didn’t use the Mixin str, the class CarBrand would not have a __add__ method, and we were not able to concatenate it with the string. Try it out. Copy the code, paste it into your interpreter, and try to remove the Mixin.
Inheritance happens from left to right, by the way, so if we have two Mixins and a base class (str is considered the Mixin, Enum is considered the base class), like class CarBrand(str, someOtherClass, Enum), methods are overridden from left to right in case classes contain the same method(s).
Dataclasses
Dataclasses were designed to reduce the typical boilerplate code to create simple data-holding classes. Dataclasses automatically generate common methods, such as __init__(), __repr__(), __eq__(), __hash__(), and __str__() based on the defined class variables. This saves you from writing repetitive code and reduces the chances of errors.
By default, Dataclasses are mutable, but you can make them immutable with the frozen=True parameter. Let’s use the same example again as before:
from dataclasses import dataclass
from enum import Enum, unique
@unique
class CarBrand(Enum):
VOLVO = "volvo"
BMW = "bmw"
VW = "volkswagen"
@dataclass(frozen=True)
class Car:
type: str
brand: CarBrand
mileage: int
volvo = Car(type="318i", brand=CarBrand.BMW, mileage=1000)
volvo.brand = CarBrand.VOLVO
The code above should result in an error, as after instantiation, the dataclass cannot be changed again (as we have given the parameter frozen=True):
Traceback (most recent call last):
File "/home/erik/Development/test-cases/enumerations.py", line 17, in <module>
volvo.brand = CarBrand.VOLVO
^^^^^^^^^^^
File "<string>", line 4, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field 'brand'
If you still use a Python version ≤ 3.5, you might want to look at attrs (though they’re convinced it is still useful even after the introduction of dataclasses).
Thanks for reading.
Python’s Hidden Gems: 3 Must-Know Functionalities was originally published in Better Programming on Medium, where people are continuing the conversation by highlighting and responding to this story.