Dynamically determine base classes on instantiation

Hans Mulder hansmu at xs4all.nl
Thu Aug 16 11:10:43 EDT 2012


On 16/08/12 14:52:30, Thomas Bach wrote:
> On Thu, Aug 16, 2012 at 12:16:03AM +0000, Steven D'Aprano wrote:
>> > Some comments:
>> > 
>> > 1) What you show are not "use cases", but "examples". A use-case is a 
>> > description of an actual real-world problem that needs to be solved. A 
>> > couple of asserts is not a use-case.
> Thanks for the clarification on that one. So, here's the use-case: I'm
> querying the crunchbase API which returns JSON data and is rather
> poorly documented. I want to create a data model for the companies
> listed on Crunchbase in order to be able to put the queried data in a
> data-base. As I am too lazy to examine all the data by hand I thought
> I automatize this. I thought that it would be nice to be able to pass
> a function a parsed JSON object (AFAIK these are lists, dicts,
> strings, ints, floats, strs in Python) and it returns me the type of
> these objects. For the simple classes (str, int, float) this is quite
> trivial: F('foo') should return `str' and F(8) should return `int'.
> 
> For a compound object like dict I would like it to return the data
> fields with their type. Hence, F({'foo': 8}) should return 
> {'foo': int}, and given that f = F({'foo': {'bar': 80}}) I would like
> f to equal to {'foo': dict}, with the option to query the type of
> 'foo' via f.foo, where the latter should equal to {'bar': int}. So
> far, this is not a complicated case. But, sometimes a data field on
> returned data set is simply None. Thus, I want to extract the types from
> another data set and merge the two.
> 
> So, my question (as far as I can see it, please correct me if I am
> wrong) is less of the "How do I achieve this?"-kind, but more of the
> "What is a clean design for this?"-kind. My intuitive thought was that
> the `merge' function should be a part of the object returned from `F'.

The misunderstanding is that you feel F should return an object with
a 'merge' method and a varying abse type, while Steven and others
think that F should be a function.

Maybe something like:

def F(obj):
    if obj is None:
        return None
    tp = type(obj)
    if tp in (bool, int, float, str):
        return tp
    elif tp is list:
        return merge([F(elem) for elem in obj])
    elif tp is dict:
        return dict((k, F(v)) for k,v in obj.iteritems())
    else:
        raise ValueError("Unexpected type %s for value %s" %(tp, obj))

def merge(lst):
    if None in lst:
        not_nones = [elem for elem in lst if elem is not None]
        if not_nones:
            not_none = not_nones[0]
            lst = [not_none if elem is None else elem for elem in lst]
        else:
            return lst  # all elements are None; nothing can be done
    types = {}
    for elem in lst:
        if type(elem) is dict:
            for k,v in elem.iteritems():
                if v is None:
                    if k in types:
                        elem[k] = types[k]
                    else:
                        for other in lst:
                            if (other is not elem
                                and type(other) is dict
                                and k in other
                                and other[k] is not None
                            ):
                                elem[k] = types[k] = other[k]
                                break
    return lst


The merge logic you have in mind may be different from what I just
made up, but the idea remains: F and merge can be functions.


Hope this helps,

-- HansM






More information about the Python-list mailing list