Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Contacts what are the person objects?
-
I am confused about the person objects returned by the Contacts module. I came across this issue because I was trying to make a dataset class. I thought I should harmonise the data once read in from the source. So I thought translate the data to namedtuples. Rightly or wrongly, could have been another format. But I am guessing contacts.person is a little different. Maybe it just uses slots, I am not sure. Anyway, I went the long way around and converted the list of contacts to namedtuples. But it's slow on my iPad Pro. I have 992 contacts.
Any comments welcome. I just have a feeling I am missing something very basic here. Either speeding up the func to create a list of namedtuples or by passing it all together. Again, I am trying to get to one internal data structure format. In this case namedtuples. The idea is that data from other sources will be loaded from .json files, memory or whatever, but will land in a nice format internally.Slow motion code
import ui, editor, contacts from collections import namedtuple def objlist_to_named_tp(obj_list, filter_list = []): ''' objlist_to_named_tp: Desc: Convert a list of objects in to a list of namedtuples. params obj_list = list of objects. The objects in the list need to be able to support __dir__ filter_list = exclude any attr that appears in this list ''' tup_list = [] for obj in obj_list: d = {k:getattr(obj, k) for k in dir(obj) if not k.startswith('_') and k not in filter_list and not callable(k)} np= namedtuple('DataItem', d.keys())(**d) tup_list.append(np) return tup_list if __name__ == '__main__': lst =objlist_to_named_tp(contacts.get_all_people(), filter_list = 'vcard') p = lst[0] print(p.first_name,p.last_name, p.birthday) print('records=', len(lst)) print('*'*50) #print(p._source)
-
10 seconds --> 1 second on my iPad... The trick is to only define the namedtuple once (for the first person) instead of defining it over and over again for each person in the list.
def objlist_to_named_tp(people, filter_list=None): filter_list = filter_list or [] # avoid default mutable arguements # See: http://docs.python-guide.org/en/latest/writing/gotchas fields = (field for field in dir(people[0]) if not field.startswith('_') and field not in filter_list and not callable(field)) np = namedtuple('DataItem', fields) return [np(**{field: getattr(person, field) for field in np._fields}) for person in people]
-
@ccc , perfect. Thanks again. I Had unwound the dict comprehension, I put it back because there was no notable difference, problem was I was focusing on the wrong thing. I also,had an idea my list param was bad. I remember it's come up here on the forum before. But thanks for the link. I went and read it. The reason for the filter is to have a generic function not just for contacts. In this case, the vCard attr just seemed a little extreme in size to carry around in memory if you don't need it. I still have a little more to do. I think I will need to flatten out the fields in the namedtuples. I will worry about that later. I am pretty sure I need to do that when creating the fields for the namedtuple and then remap them so to speak. The challenge will be doing it generically. But again, it might be smarter to deal with those issues in my dataset object.
But on my iPad Pro your version is instant, my version 3 to 4 secs. Huge difference. -
@ccc , out of interest, did you try your func without passing 'vcard' to the filter? Puts a big strain on the timing