views:

131

answers:

6

I have a class that contains only fields and no methods, like this:

class Request(object):

    def __init__(self, environ):
        self.environ = environ
        self.request_method = environ.get('REQUEST_METHOD', None)
        self.url_scheme = environ.get('wsgi.url_scheme', None)
        self.request_uri = wsgiref.util.request_uri(environ)
        self.path = environ.get('PATH_INFO', None)
        # ...

This could easily be translated to a dict. The class is more flexible for future additions and could be fast with __slots__. So would there be a benefit of using a dict instead? Would a dict be faster than a class? And faster than a class with slots?

+5  A: 

Use a dictionary unless you need the extra mechanism of a class. You could also use a namedtuple for a hybrid approach:

>>> from collections import namedtuple
>>> request = namedtuple("Request", "environ request_method url_scheme")
>>> request
<class '__main__.Request'>
>>> request.environ = "foo"
>>> request.environ
'foo'

Performance differences here will be minimal, although I would be surprised if the dictionary wasn't faster.

katrielalex
"Performance differences here will be **minimal**, although I would be surprised if the dictionary wasn't **significantly** faster." This does not compute. :)
mipadi
@mipadi: this is true. Now fixed :p
katrielalex
+2  A: 

A class in python is a dict underneath. You do get some overhead with the class behavior, but you won't be able to notice it without a profiler. In this case, I believe you benefit from the class because:

  • All your logic lives in a single function
  • It is easy to update and stays encapsulated
  • If you change anything later, you can easily keep the interface the same
Bruce Armstrong
+1  A: 

I would recommend a class, as it is all sorts of information involved with a request. Were one to use a dictionary, I'd expect the data stored to be far more similar in nature. A guideline I tend to follow myself is that if I may want to loop over the entire set of key->value pairs and do something, I use a dictionary. Otherwise, the data apparently has far more structure than a basic key->value mapping, meaning a class would likely be a better alternative.

Hence, stick with the class.

Stigma
I totally disagree. There's no reason to restrict the use of dictionaries to things to iterate over. They're for maintaining a mapping.
katrielalex
Read a bit more closely, please. I said _may want to loop over_, not _will_. To me, using a dictionary implies there is a big functional similarity between the keys and values. For example, names with ages. Using a class would mean the various 'keys' have values with vastly different meanings. For example, take a class PErson. Here, 'name' would be a string, and 'friends' may be a list, or a dictionary, or some other suitable object. You wouldn't loop over all these attributes as part of normal usage of this class.
Stigma
I think the distinction between classes and dictionaries is made indistinct in Python by the fact that the former are implemented using the latter ('slots' not withstanding). I know this confused me a bit when I was first learning the language (along with the fact that classes were objects and therefore instances of some mysterious metaclasses).
martineau
+5  A: 

Why on earth would you make this a dictionary? What's the advantage? What happens if you later want to add some code? Where would your __init__ code go?

Classes are for bundling related data (and usually code).

Dictionaries are for storing key-value relationships, where usually the keys are all of the same type, and all the values are also of one type. Occasionally they can be useful for bundling data when the key/attribute names are not all known up front, but often this a sign that something's wrong with your design.

Keep this a class.

adw
I would create a kind of factory method creating a dict instead of the class' `__init__` method. But you're right: I would separate to things that belong together.
deamon
+1  A: 

I agree with the last poster. I would never represent an "object" (in an OO sense) with a dictionary. Dictionaries aggregate name/value pairs. Classes represent objects. I've seen code where the objects are represented with dictionaries and it's unclear what the actual shape of the thing is. What happens when certain name/values aren't there? What restricts the client from putting anything at all in. Or trying to get anything at all out. The shape of the thing should always be clearly defined.

When using Python it is important to build with discipline as the language allows many ways for the author to shoot him/herself in the foot.

jaydel
Answers on SO are sorted by votes, and answers with the same vote count are randomly ordered. So please clarify whom you mean by "the last poster".
Mike DeSimone
And how do you know that something that has only fields and no functionality is an "object" in an OO sense?
Muhammad Alkarouri
+1  A: 

It may be possible to have your cake and eat it, too. In other words you can create something that provides the functionality of both a class and dictionary instance. See the ActiveState's Dictionary with attribute-style access recipe and comments on ways of doing that.

If you decide to use a regular class rather than a subclass, I've found the 'simple but handy "collector of a bunch of named stuff" class' recipe to be very flexible and useful for the sort of thing it looks like you're doing (i.e. create a relative simple aggregator of information). Since it's a class you can easily extend its functionality later by adding methods.

Lastly it should be noted that the names of class members must be legal Python identifiers, but dictionary keys do not -- so a dictionary would provide greater freedom in that regard because keys can be anything hashable (even something that's not a string).

martineau