HiveBrain v1.2.0
Get Started
← Back to all entries
snippetpythonMinor

A better way to convert an SQLObject instance into a dict

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
dictsqlobjectconvertintowaybetterinstance

Problem

I've got this function which returns an SQLObject instance as a dict (taking into account inherited classes, properties, etc). It doesn't work right now on SQLObject classes which inherit from another class but add new attributes, so that's a work in progress, but I feel like this could be done smarter/better in Python.

What do you think?

PS the purpose of this is to allow a generic presentation of an object as a JSON document. It returns a dict which can be then given to json.dumps. If you've got a different way to convert an SQLObject to a JSON doc, that would be cool as well

def sqlobject_to_dict(obj):
    obj_dict = {}
    cls_name = type(obj)
    has_props = False
    for attr in vars(cls_name):
        attr_parent = type(getattr(obj, attr)).__bases__[0]
        if isinstance(getattr(cls_name, attr), property):
            has_props = True
            if isinstance(getattr(obj, attr), Decimal):
                obj_dict[attr] = float(getattr(obj, attr))
            elif isinstance(getattr(obj, attr), list):
                dict_list = []
                for list_item in getattr(obj, attr):
                    dict_list.append(sqlobject_to_dict(list_item))
                obj_dict[attr] = dict_list
            elif isinstance(getattr(obj, attr), dict):
                dict_dict = {}
                for key, val in getattr(obj, attr):
                    dict_dict[key] = sqlobject_to_dict(val)
                obj_dict[attr] = dict_dict
            elif attr_parent == SQLObject:
                obj_dict[attr] = sqlobject_to_dict(getattr(obj, attr))
            else:
                obj_dict[attr] = getattr(obj, attr)
        elif not has_props and attr_parent != SQLObject:
            if "_get_" in attr:
                attr_name = '_'.join(attr.split('_', 3)[3:])
                if hasattr(obj, attr_name):
                    obj_dict[attr_name] = getattr(obj, attr_name)
    return obj_dict

Solution

def sqlobject_to_dict(obj):
    obj_dict = {}
    cls_name = type(obj)


That's not a name, its a class object

has_props = False
    for attr in vars(cls_name):
        attr_parent = type(getattr(obj, attr)).__bases__[0]


You have getattr(obj, attr) over and over and over. Do it once, and store it in a local variable

if isinstance(getattr(cls_name, attr), property):
            has_props = True
            if isinstance(getattr(obj, attr), Decimal):
                obj_dict[attr] = float(getattr(obj, attr))
            elif isinstance(getattr(obj, attr), list):
                dict_list = []
                for list_item in getattr(obj, attr):
                    dict_list.append(sqlobject_to_dict(list_item))
                obj_dict[attr] = dict_list


I recommend doing obj_dict[attr] = map(sql_object_dict, getattr(obj, attr))

elif isinstance(getattr(obj, attr), dict):
                dict_dict = {}
                for key, val in getattr(obj, attr):


Don't you need .items()?
dict_dict[key] = sqlobject_to_dict(val)
obj_dict[attr] = dict_dict

I'd do obj_dict[attr] = dict( (key, sql_object_to_dict(value)) for key, value in getattr(obj, attr) )
elif attr_parent == SQLObject:

Why did you fetch attr_parent instead of using isinstance?

obj_dict[attr] = sqlobject_to_dict(getattr(obj, attr))
            else:
                obj_dict[attr] = getattr(obj, attr)


Is a default really a good idea? There may some sort of attribute with isn't valid JSON that makes it through.

elif not has_props and attr_parent != SQLObject:

            if "_get_" in attr:
                attr_name = '_'.join(attr.split('_', 3)[3:])


Thats a confusing way to do that. I'm sure what exactly the form you are trying to match here is, but I think this is a use case for regular expressions.

if hasattr(obj, attr_name):
                    obj_dict[attr_name] = getattr(obj, attr_name)


So I'm guessing you've got various _get_foo() functions which are invoked by some sort of __getattr__ magic. You stop checking for this once you find a property. (Probably newer objects use properties instead.) I would consider not doing the has_props thing. It makes your code less clear, and probably doesn't make much difference performance wise.

return obj_dict

Code Snippets

def sqlobject_to_dict(obj):
    obj_dict = {}
    cls_name = type(obj)
has_props = False
    for attr in vars(cls_name):
        attr_parent = type(getattr(obj, attr)).__bases__[0]
if isinstance(getattr(cls_name, attr), property):
            has_props = True
            if isinstance(getattr(obj, attr), Decimal):
                obj_dict[attr] = float(getattr(obj, attr))
            elif isinstance(getattr(obj, attr), list):
                dict_list = []
                for list_item in getattr(obj, attr):
                    dict_list.append(sqlobject_to_dict(list_item))
                obj_dict[attr] = dict_list
elif isinstance(getattr(obj, attr), dict):
                dict_dict = {}
                for key, val in getattr(obj, attr):
obj_dict[attr] = sqlobject_to_dict(getattr(obj, attr))
            else:
                obj_dict[attr] = getattr(obj, attr)

Context

StackExchange Code Review Q#7420, answer score: 4

Revisions (0)

No revisions yet.