Explain Codes LogoExplain Codes Logo

Python dictionary from an object's fields

python
object-oriented-programming
dataclasses
dictionary
Anton ShumikhinbyAnton Shumikhin·Dec 16, 2024
TLDR

To easily create a dictionary from an object's fields, employ vars(obj) or obj.__dict__. These methods generate a dictionary mapping field names to associated values.

Example:

class MyClass: def __init__(self, name, value): self.name = name self.value = value obj = MyClass('apple', 42) # Say hello to our object fields_as_dict = vars(obj) # or obj.__dict__, either works like a charm

Result:

{'name': 'apple', 'value': 42} # Voila, a dictionary

These tricks will exclude methods and class variables. They're designed for objects with a __dict__ attribute and may not work for all object types.

Dictionary behavior: dict inheritance

You can make an object behave like a dictionary by inheriting from dict. This is convenient when you want to directly use dictionary methods on the object.

class MyClass(dict): def __init__(self, some, stuff): super().__init__(some, stuff) obj = MyClass('pie', 3.14) # Pie, anyone? # This object behaves like a dictionary... How cool is that?

Converting through Iteration: Implement __iter__

Implement the __iter__ method in your class to allow Iterable-to-Dict conversion with the built-in dict() function.

class MyClass: ... def __iter__(self): for attr, val in self.__dict__.items(): yield (attr, val) obj = MyClass(...) converted_dict = dict(obj) # Isn't Python just beautiful?

Avoiding Methods & Private Attributes

Sometimes you'll want to exclude methods and private attributes (those names prefixed with __). Use a dictionary comprehension to filter out these unwanted extras from your end result.

class MyClass: ... obj = MyClass(...) new_dict = { attr: val for attr, val in obj.__dict__.items() if not callable(val) and not attr.startswith('__') } # Handy-dandy filtration, works like a coffee filter

Introduction to object_to_dict Function

When converting objects to dictionaries is a frequent task, creating a dedicated function helps streamline the process:

import inspect def object_to_dict(obj): return { attr: val for attr, val in inspect.getmembers(obj) if not attr.startswith('__') and not inspect.ismethod(val) } # Saying goodbye to messy work, one method at a time! fields_as_dict = object_to_dict(obj)

Harmonizing with Class Decorators

When object-to-dictionary conversion becomes common in your code, the @dataclass decorator simplifies the process by including a built-in asdict() method.

from dataclasses import dataclass @dataclass # Decorated, not with icing but with '@dataclass', equally sweet. class MyClass: name: str value: int obj = MyClass('pizza', 33) # Who can say no to pizza?

Smarter with getattr: Covering all Grounds

When a class uses @property decorators or computed attributes, vars() and __dict__ won't capture those. But getattr() will!

class MyClass: @property def computed(self): return 'computed value' # Because freedom of expression! obj = MyClass() dict_vers = { attr: getattr(obj, attr) for attr in dir(obj) if not attr.startswith('__') and not callable(getattr(obj, attr)) } # Nothing escapes this one, even the computed values

Best of Both Worlds: Class & Instance Dictionaries

Why choose when you can combine class attributes and instance attributes in a single dictionary?!

class MyClass: class_var = '1' # Classy! def __init__(self): self.instance_var = '2' # Instantly available combined = {**MyClass.__dict__, **obj.__dict__} # Best of both worlds combined = {k: v for k, v in combined.items() if not (k.startswith('__') or callable(v))}