5
\$\begingroup\$

I've got a collection of users with two types of IDs (a_id, b_id) where one is a positive integer and the other is a six-letter string. For my collection class, I'd like to be able to look up users using either type of ID.

Is there something wrong with using __contains__ and __getitem__ for either type of ID?

class UserList: def __init__(self, users_json): self.a_ids = {} self.b_ids = {} for user in users_json: a_id = user['a_id'] b_id = user['b_id'] self.a_ids[a_id] = user self.b_ids[b_id] = user def __contains__(self, some_id): return some_id in self.a_ids or some_id in self.b_ids def __getitem__(self, some_id): try: return self.a_ids[some_id] except KeyError: return self.b_ids[some_id] 

Update: This is for Python 3.x, and there is no implementation of __setitem__; updating users is handled in separate API functions.

\$\endgroup\$
2
  • \$\begingroup\$Would you be willing to provide more code? Do you have a __setitem__? Are you using Python 3.3+? The answer to all of these could make a drastically different answer.\$\endgroup\$
    – Peilonrayz
    CommentedOct 24, 2017 at 9:49
  • \$\begingroup\$@Peilonrayz: Thanks for your input. I've clarified on those two questions: No, and yes.\$\endgroup\$
    – sshine
    CommentedOct 24, 2017 at 13:35

1 Answer 1

6
\$\begingroup\$
  • From Python 3.3, the collections module added collections.ChainMap. Utilizing this class can simplify your code.
  • You should probably make self.a_ids and self.b_ids a list. And index to get which one you want, such as self.ids[0]. This list is created when using ChainMap anyway too.

And so I'd change your code to something more like:

from collections import ChainMap class UserList: def __init__(self, users): self._lookup = ChainMap({}, {}) self.ids = self._lookup.maps for user in users: self.ids[0][user['a_id']] = user self.ids[1][user['b_id']] = user def __contains__(self, some_id): return some_id in self._lookup def __getitem__(self, some_id): return self._lookup[some_id] 

Alternately, you could subclass ChainMap, and not need to write any of the methods.

from collections import ChainMap class UserList(ChainMap): def __init__(self, users): super().__init__({}, {}) for user in users: self.maps[0][user['a_id']] = user self.maps[1][user['b_id']] = user 

However, at that point, there's not much benefit to using a class. And so I'd just use a raw ChainMap.

\$\endgroup\$

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.