4
\$\begingroup\$

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
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$
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
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Excellent advice. Let me factor this all in. I'm using attr_parent because I'm working on getting the properties of the inherited class. \$\endgroup\$
    – tkone
    Commented Jan 3, 2012 at 20:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.