0

The Python MongoDB driver, PyMongo, returns results as dictionaries. I'm trying to figure out the best way to use such a dictionary in an object constructor.

  1. Keep the dictionary as an attribute

    self.dict = building_dict
    

    Then each property of the building would be reachable through building.dict["property"].

    A better attribute name could be used. Maybe a one-letter attribute. This doesn't look so elegant.

  2. Parse dictionary to create attributes

    self.name = building_dict['name']
    self.construction_date = building_dict['construction_date']
    ...
    

    In my model, the dictionaries can be pretty big but this task can be automated in the constructor to perform actions/checks on the values before or after the assignment.

Edit: The use of getters/setters is independent of options 1. and 2. above.

In solution 2., I'd avoid name collision between attributes and their getters by prefixing all dictionary keys by an underscore before making them attributes.

As a side-issue, the dictionary may contain the description of embedded documents, so the constructor should go through the whole dictionary to seek embedded documents that have their specific class in the code and instantiate those classes right away.

Update

I'll most probably use an ODM such as MongoEngine for my project and it will deal with those issues.

Outside of this specific use case (link with MongoDB, existing ODMs,...), the question is still relevant so I'm leaving below the best answer I could come up with.

Community
  • 1
  • 1
Jérôme
  • 13,328
  • 7
  • 56
  • 106

2 Answers2

1

The best you can do is to create an object. You can instantiate a classwith your dict like this:

building_dict = {'property': 4, 'name': 'my name'}   # example dict
my_item = type('MyClass', (), building_dict)         # instantiating class MyClass

You can access it afterwards like every other object:

print(my_item.property)
# 4
print(my_item.name)
# my name
Nhor
  • 3,860
  • 6
  • 28
  • 41
  • Interesting. This makes solution 2 quite easy to implement. Specific actions, like checks, can be made before and after if needed. It can be mixed with the getters/setters approach if needed. – Jérôme Nov 12 '15 at 14:29
  • You can also inherit a `class` in the `()` if you need those `object`s to contain some common functions or values – Nhor Nov 12 '15 at 14:32
  • Using a class method, there should be a way to do this inside a constructor, so that I can do some checks on the values before/after they are assigned to attributes. – Jérôme Nov 12 '15 at 14:52
  • Of course you can create your own constructor if you need some more complex logic implemented into your `object` creation. I just posted the most intuitive solution of how to create `object` with a `dict` – Nhor Nov 12 '15 at 14:54
0

My favorite solution so far stores elements as attributes and uses getters/setters:

class Building(object):

    def __init__(self, dictionary):

        # Check the values
        # ...

        # Find sub-dictionaries describing instances of another class
        # stored as embedded documents in the base, call their 
        # constructor on sub-directories, then replace each sub-directory
        # with the corresponding class instance.
        # ...

        # Set attributes from dictionary
        for key in dictionary:
            setattr(self, '_'+key, dictionary[key])

        # Add default values if needed, etc.
        # ...

    # Usual getter/setter stuff
    @property
    def name(self):
        try:
            return self._name
        except AttributeError as e:
            # deal with missing name
Jérôme
  • 13,328
  • 7
  • 56
  • 106