Addison
Addison

Reputation: 1075

Python context objects better to use dictionary or attributes?

In my Python app, I need to create a simple RequestContext object that contains the actual request to send, as well as some other metadata about the request, e.g. index, id, source, etc. Also, it's likely that more metadata will be added.

I can think of two ways to do this:

Option 1: Attributes of the RequestContext:

class RequestContext(object):
  def __init__(self, request, index=0, source=None):
    self.request = request
    self.index = index
    self.source = source
    ...

Option 2: Dictionary in the RequestContext:

class RequestContext(object):
  def __init__(self, request):
    self.request = request
    self.context_info = {}

Then users can add whatever context info they want.

I personally like accessing values through attributes, because you have a predefined set of attributes that you know are there.

On the other hand, a dictionary lets the client code (owned by me) add more metadata without having to update the RequestContext object definition.

So which one would be better in terms of ease of use and ease of adding more metadata? Are there other pitfalls or considerations that I should think about?

Upvotes: 2

Views: 570

Answers (1)

abarnert
abarnert

Reputation: 365875

First, you seem to be operating under a misapprehension:

On the other hand, a dictionary lets the client code (owned by me) add more metadata without having to update the RequestContext object definition.

You don't have to update the class definition to add new attributes. (You can force the class to have a fixed set of attributes in various ways—e.g., by using __slots__. But if you don't do any of that, you can add new attributes on the fly.) For example:

>>> class C(object):
...     def __init__(self, x):
...         self.x = x
>>> c = C(10)
>>> c.y = 20
>>> print(c.x, c.y)
10 20

In fact, if you look under the covers, attributes are (by default) stored in a perfectly normal dictionary, named __dict__:

>>> print(c.__dict__)
{'x': 10, 'y': 20}

So, what is the difference between using attributes, vs. just adding a dictionary attribute and using members of that dictionary (or, alternatively, inheriting from or delegating to a dict)?

Really, it's the same as the difference between using separate variables vs. a single dict at the top level.

One way to look at it is whether the name-value pairs are data, or whether the names are part of your program and only the values are data. In the former case, you want a dict; in the latter case, you want separate variables.

Alternatively, you can ask how dynamic the names are. If there's an open-ended set of values whose names are only known at runtime, you want a dict. If there's a fixed set of values whose names are hardcoded into your source, you want attributes.

Finally, just ask yourself how often you'd have to use getattr and setattr if you went with attributes. If the answer is "frequently", you want a dict; if it's "never", you want attributes.

In many real-life apps, it's not entirely clear, because you're somewhere between the two. Sometimes, rethinking your design can make it clearly one or the other, but sometimes things are just inherently "sort of dynamic". In that case, you have to make a judgment call: decide which of the two cases you're closest to, and code as if that were the real case.

It may be worth looking at some real-life open source apps that are similar to yours. For example, you're dealing with metadata about some kind of requests. Maybe look at how requests and pycurl deal with HTTP information that's kind of like metadata, like headers and status lines. Or maybe look at how QuodLibet and MusicBrainz Picard deal with metadata in a different domain, music files. And so on.

Upvotes: 1

Related Questions