Skip to content

Instantly share code, notes, and snippets.

@adrian-castravete
Last active February 13, 2019 10:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adrian-castravete/5883447 to your computer and use it in GitHub Desktop.
Save adrian-castravete/5883447 to your computer and use it in GitHub Desktop.
Objectify a dictionary, or act as a decorator and objectify the return value of the decorated function. Objectify means getting a dictionary, and assigning attributes to the dictionary given its keys or newer assignments.
#!/usr/bin/env python
"""Scrap module.
Just tiny bits & bolts.
.. author: Adrian Castravete
"""
from functools import wraps
def objectify(func):
"""Mimic an object given a dictionary.
Given a dictionary, create an object and make sure that each of its
keys are accessible via attributes.
If func is a function act as decorator, otherwise just change the dictionary
and return it.
:param func: A function or another kind of object.
:returns: Either the wrapper for the decorator, or the changed value.
Example::
>>> obj = {'old_key': 'old_value'}
>>> oobj = objectify(obj)
>>> oobj['new_key'] = 'new_value'
>>> print oobj['old_key'], oobj['new_key'], oobj.old_key, oobj.new_key
>>> @objectify
... def func():
... return {'old_key': 'old_value'}
>>> obj = func()
>>> obj['new_key'] = 'new_value'
>>> print obj['old_key'], obj['new_key'], obj.old_key, obj.new_key
"""
def create_object(value):
"""Create the object.
Given a dictionary, create an object and make sure that each of its
keys are accessible via attributes.
Ignore everything if the given value is not a dictionary.
:param value: A dictionary or another kind of object.
:returns: Either the created object or the given value.
"""
if isinstance(value, dict):
# Build a simple generic object.
class Object(dict):
def __setitem__(self, key, val):
setattr(self, key, val)
return super(Object, self).__setitem__(key, val)
# Create that simple generic object.
ret_obj = Object()
# Assign the attributes given the dictionary keys.
for key, val in value.iteritems():
ret_obj[key] = val
setattr(ret_obj, key, val)
return ret_obj
else:
return value
# If func is a function, wrap around and act like a decorator.
if hasattr(func, '__call__'):
@wraps(func)
def wrapper(*args, **kwargs):
"""Wrapper function for the decorator.
:returns: The return value of the decorated function.
"""
value = func(*args, **kwargs)
return create_object(value)
return wrapper
# Else just try to objectify the value given.
else:
return create_object(func)
@jacquesfize
Copy link

jacquesfize commented Jul 24, 2018

Hey adrian !

Thank you for this gist ;) Just a two things, you might change :

  • First, ìteritems()` only works in Python2.x.
  • Second, if the dict contains other dicts, they are not "objectified"! You can change this using the following code modifications :
def objectify(func):
    def create_object(value):
        if isinstance(value, dict):
            # Build a simple generic object.
            class Object(dict):
                def __setitem__(self, key, val):
                    setattr(self, key, val)
                    return super(Object, self).__setitem__(key, val)

            # Create that simple generic object.
            ret_obj = Object()
            # Assign the attributes given the dictionary keys.
            for key, val in value.items():
                if isinstance(val,dict): # Modfications starts here !
                    ret_obj[key] = objectify(val)
                else:
                    ret_obj[key] = val
                setattr(ret_obj, key, ret_obj[key])
            return ret_obj
        else:
            return value

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment