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 -- http://mail.python.org/mailman/listinfo/python-list