Introduction to Python Libraries: attrs, bidict, Box, dataclasses, and DottedDict
This article introduces five Python libraries—attrs, bidict, Box, dataclasses, and DottedDict—explaining their installation, core features, and practical code examples for simplifying data class creation, bidirectional mapping, nested data access, and configuration management.
1. attrs
attrs is a library that simplifies Python class definitions by automatically generating __init__, __repr__, __eq__, and other special methods.
Installation:
pip install attrsExample – basic usage:
import attr
@attr.s
class Person:
name = attr.ib()
age = attr.ib()
p = Person(name="Alice", age=30)
print(p) # Output: Person(name='Alice', age=30)Example – default values:
@attr.s
class Person:
name = attr.ib(default="Unknown")
age = attr.ib(default=0)
p = Person(age=30)
print(p) # Output: Person(name='Unknown', age=30)Example – validator:
def positive_number(instance, attribute, value):
if value < 0:
raise ValueError("Age must be a positive number")
@attr.s
class Person:
name = attr.ib()
age = attr.ib(validator=positive_number)
try:
p = Person(name="Alice", age=-1)
except ValueError as e:
print(e) # Output: Age must be a positive numberExample – converter:
@attr.s
class Person:
name = attr.ib(converter=str)
age = attr.ib(converter=int)
p = Person(name=123, age="30")
print(p) # Output: Person(name='123', age=30)Example – frozen instance:
@attr.s(frozen=True)
class Person:
name = attr.ib()
age = attr.ib()
p = Person(name="Alice", age=30)
try:
p.age = 31
except attr.exceptions.FrozenInstanceError as e:
print(e) # Output: can't set attributes of frozen PersonUse case: Quickly define data classes for configuration objects, DTOs, etc.
2. bidict
bidict provides a bidirectional mapping where keys can be accessed as values and vice versa.
Installation:
pip install bidictExample – basic usage:
from bidict import bidict
b = bidict({"a": 1, "b": 2})
print(b["a"]) # Output: 1
print(b.inv[1]) # Output: 'a'Example – add new item:
b = bidict({"a": 1, "b": 2})
b["c"] = 3
print(b) # Output: bidict({'a': 1, 'b': 2, 'c': 3})Example – delete item:
b = bidict({"a": 1, "b": 2})
del b["a"]
print(b) # Output: bidict({'b': 2})Example – existence check:
b = bidict({"a": 1, "b": 2})
print("a" in b) # Output: True
print(1 in b.inv) # Output: TrueExample – update multiple items:
b = bidict({"a": 1, "b": 2})
b.update({"c": 3, "d": 4})
print(b) # Output: bidict({'a': 1, 'b': 2, 'c': 3, 'd': 4})Use case: Useful for bidirectional look‑ups in NLP, database reverse mapping, etc.
3. Box
Box is a Python dictionary with advanced dot‑notation access, making nested data handling more convenient.
Installation:
pip install python-boxExample – basic usage:
from box import Box
data = {
"person": {
"name": "Alice",
"age": 30,
"address": {
"street": "123 Main St",
"city": "Anytown"
}
}
}
box_data = Box(data)
print(box_data.person.name) # Output: AliceModify nested data:
box_data.person.age = 31
print(box_data) # Shows updated ageAdd new field:
box_data.person.email = "[email protected]"
print(box_data) # Shows email addedLoad data from a JSON file:
import json
with open('data.json') as f:
data = json.load(f)
box_data = Box(data)
print(box_data.person.name) # Output: AliceConvert back to a plain dict:
dict_data = box_data.to_dict()
print(dict_data) # Output: standard dictionaryUse case: Ideal for configuration management and JSON data manipulation.
4. dataclasses
dataclasses is part of the Python standard library that simplifies the creation of data classes by auto‑generating __init__, __repr__, __eq__, and more.
Example – basic usage:
from dataclasses import dataclass
@dataclass
class Person:
name: str
age: int
p = Person(name="Alice", age=30)
print(p) # Output: Person(name='Alice', age=30)Example – default values:
@dataclass
class Person:
name: str = "Unknown"
age: int = 0
p = Person(age=30)
print(p) # Output: Person(name='Unknown', age=30)Example – object comparison:
p1 = Person(name="Alice", age=30)
p2 = Person(name="Alice", age=30)
print(p1 == p2) # Output: TrueExample – immutable (frozen) dataclass:
@dataclass(frozen=True)
class Person:
name: str
age: int
p = Person(name="Alice", age=30)
try:
p.age = 31
except FrozenInstanceError as e:
print(e) # Output: cannot assign to field 'age'Example – inheritance:
@dataclass
class Employee(Person):
employee_id: int
e = Employee(name="Bob", age=35, employee_id=123)
print(e) # Output: Employee(name='Bob', age=35, employee_id=123)Use case: Perfect for simple DTOs, configuration objects, and any scenario needing concise data containers.
5. DottedDict
DottedDict offers lightweight dot‑path access to nested dictionaries and lists, similar to Box.
Installation:
pip install dotted-dictExample – basic usage:
from dotted_dict import DottedDict
data = {
"person": {
"name": "Alice",
"age": 30,
"address": {
"street": "123 Main St",
"city": "Anytown"
}
}
}
dotted_data = DottedDict(data)
print(dotted_data.get("person.name")) # Output: AliceModify nested data:
dotted_data.set("person.age", 31)
print(dotted_data.to_dict()) # Shows updated ageAdd new field:
dotted_data.set("person.email", "[email protected]")
print(dotted_data.to_dict()) # Shows email addedLoad from JSON file:
import json
with open('data.json') as f:
data = json.load(f)
dotted_data = DottedDict(data)
print(dotted_data.get("person.name")) # Output: AliceConvert back to dict:
dict_data = dotted_data.to_dict()
print(dict_data) # Output: standard dictionaryUse case: Suitable for frequent nested dict/list manipulation in configuration management and JSON processing.
Test Development Learning Exchange
Test Development Learning Exchange
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.