9

to conserve memory & avoid redundant DB storage (yes possibly pre-optimizing), I'm using namedtuple instead of dictionary.

But I need to search the collection of recs and my dictionary approach is:

import operator
def query(D,key,val, keynotfound=None):
    '''
    D:  a list of dictionaries  (but I want it to be namedtuples)
    key:  the key to query
    val:  the value to search for
    keynotfound:  value if key is not found

    Returns elements in D such that operator(D.get(key,None), val) is true
    '''
    op = operator.eq
    def try_op(f,x,y):
        try:
            return f(x,y)
        except Exception, exc:
            return False

    return (x for x in D if try_op(op, x.get(key,keynotfound),val))

not working on namedtuple Any tips on how to subclass namedtuple to make it searchable like a dict? And not every instance will contain the same key/fields as the query-key so I need to skip that row rather than throw a key/attr error..

Dewey
  • 756
  • 6
  • 17
  • I'd like this query function to work for both data-types, so rather than change get to getattr, I believe I'll subclass namedtuple and add a "get" method that calls getattr so the interface remains the same......any problems with that?? – Dewey Feb 28 '15 at 21:27

3 Answers3

16

I think you can use getattr to see if the field exists and either raise an exception or return a default value if it doesn't.

For example, based on the namedtuple documentation:

from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])

# An instance of the namedtuple
p = Point(1, 2)

In [1]: getattr(p, "x")
Out[1]: 1

In [2]: getattr(p, "z")
...
AttributeError: 'Point' object has no attribute 'z'

In [3]: getattr(f, "z", None)
Out[3]: None
erik-e
  • 3,721
  • 1
  • 21
  • 19
1

Try this:

return (x for x in D if try_op(op, getattr(x,key,keynotfound),val))

getattr works similar for attributes as get for dictionary elements.

Juergen
  • 12,378
  • 7
  • 39
  • 55
1

The best solution is to call vars(p), assuming p is your namedtuple instance. This gives a collections.OrderedDict that you can use like a normal dictionary.

Peter Shinners
  • 3,686
  • 24
  • 24
  • 2
    No longer works as of 3.4, as namedtuple no longer implements `__dict__`. namedtuple's `_asdict` method should be used instead. – TakingItCasual Oct 09 '18 at 11:35