Should I use a class or dictionary?

I have a class that contains only fields and no methods, for example:

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 can easily be translated into a dict. The class is more flexible for future additions and can be faster with __slots__ . So would it be useful to use a dict? Will dictate faster than class? And faster than a class with slots?

+84
python dictionary oop class
Oct 28 2018-10-28
source share
9 answers

Why did you make this dictionary? What is the advantage? What happens if you later want to add code? Where does your __init__ code go?

Classes are designed to bind related data (and usually code).

Dictionaries are intended for storing key-value relations, where usually the keys are of the same type, and all values ​​are also of the same type. Sometimes they can be useful for combining data when key / attribute names are not all known in advance, but often this is a sign that something is wrong with your design.

Keep it in class.

+24
Oct 28 '10 at 17:18
source share

Use a dictionary if you do not need an additional class mechanism. You can also use 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' 

The differences in performance here will be minimal, although I would be surprised if the dictionary were not faster.

+38
Oct 28 2018-10-28
source share

The class in python is underneath. You get some overhead on the class’s behavior, but you won’t be able to notice it without a profiler. In this case, I believe that you are using a class because:

  • All your logic lives in one function
  • Easily updated and stays encapsulated.
  • If you change anything later, you can easily maintain the interface with the same
+35
Oct 28 '10 at 17:00
source share

I think that using each of them is too subjective for me to do this, so I will just stick to the numbers.

I compared the time it takes to create and change a variable in the dict, new_style class and the new_style class with slots.

Here is the code I used to test it (it's a little dirty, but it does the job.)

 import timeit class Foo(object): def __init__(self): self.foo1 = 'test' self.foo2 = 'test' self.foo3 = 'test' def create_dict(): foo_dict = {} foo_dict['foo1'] = 'test' foo_dict['foo2'] = 'test' foo_dict['foo3'] = 'test' return foo_dict class Bar(object): __slots__ = ['foo1', 'foo2', 'foo3'] def __init__(self): self.foo1 = 'test' self.foo2 = 'test' self.foo3 = 'test' tmit = timeit.timeit print 'Creating...\n' print 'Dict: ' + str(tmit('create_dict()', 'from __main__ import create_dict')) print 'Class: ' + str(tmit('Foo()', 'from __main__ import Foo')) print 'Class with slots: ' + str(tmit('Bar()', 'from __main__ import Bar')) print '\nChanging a variable...\n' print 'Dict: ' + str((tmit('create_dict()[\'foo3\'] = "Changed"', 'from __main__ import create_dict') - tmit('create_dict()', 'from __main__ import create_dict'))) print 'Class: ' + str((tmit('Foo().foo3 = "Changed"', 'from __main__ import Foo') - tmit('Foo()', 'from __main__ import Foo'))) print 'Class with slots: ' + str((tmit('Bar().foo3 = "Changed"', 'from __main__ import Bar') - tmit('Bar()', 'from __main__ import Bar'))) 

And here is the result ...

Creature...

 Dict: 0.817466186345 Class: 1.60829183597 Class_with_slots: 1.28776730003 

Variable change ...

 Dict: 0.0735140918748 Class: 0.111714198313 Class_with_slots: 0.10618612142 

So, if you just save variables, you need speed, and you don’t need a lot of calculations, I recommend using dict (you can always just make a function that looks like a method). But, if you really need classes, remember - always use __ slots __ .

Note:

I tested a class with classes and new_style and old_style. It turns out that old_style classes are faster to create, but slower to modify (but not by much, but significantly if you create many classes in a narrow loop (hint: you are doing it wrong)).

Also, the time it takes to create and modify variables may vary on your computer, as it is my old and slow one. Make sure you check it yourself to see the "real" results.

Edit:

I later tested namedtuple: I can't change it, but it took 1.4 seconds to create 10,000 samples (or something like that), so the dictionary is really the fastest.

If I change the dict function to include keys and values ​​and return dict instead of the variable containing dict, when I create it, it gives me 0.65 instead of 0.8 seconds.

 class Foo(dict): pass 

Creating is like a class with slots, and changing the variable is the slowest (0.17 seconds), so these classes are not used . switch to dict (speed) or for a class derived from an object ("syntax candy")

+19
Apr 29 '13 at 21:10
source share

I agree with @adw. I would never have imagined an “object” (in the sense of OO) with a dictionary. Dictionaries combine name / value pairs. Classes represent objects. I saw code where objects are represented with dictionaries, and it is not clear what the actual form of the thing is. What happens when there is no specific name / values? Which limits the client from something at all. Or try to get something at all. The form of a thing should always be clearly defined.

When using Python, it is important to build with discipline, as the language allows many authors to shoot in the foot.

+11
Oct 28 '10 at 17:22
source share

I would recommend the class, as this is all the information related to the request. If I were to use a dictionary, I would expect that the data that will be stored will be much more similar in nature. The guiding principle that I usually adhere to is that if I want to iterate over the entire set of key-> value pairs and do something, I use a dictionary. Otherwise, the data appears to have a much larger structure than the basic key-> value mapping, which means that the class is likely to be a better alternative.

Therefore, stick to the class.

+5
Oct 28 '10 at 17:00
source share

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 an instance of a class and a dictionary. See the ActiveState Dɪᴄᴛɪᴏɴᴀʀʏ ᴡɪᴛʜ ᴀᴛᴛʀɪʙᴜᴛᴇ -s ᴛʏʟᴇ ᴀᴄᴄᴇss recipe and comments on how to do this.

If you decide to use a regular class rather than a subclass, I found that the recipe Tʜᴇ sɪᴍᴘʟᴇ ʙᴜᴛ ʜᴀɴᴅʏ "ᴄᴏʟʟᴇᴄᴛᴏʀ ᴏғ ᴀ ʙᴜɴᴄʜ ɴᴀᴍᴇᴅ ɴᴀᴍᴇᴅ sᴛᴜғғ" ᴄʟᴀss (written by Alex Martelli) is very flexible and useful for this kind of thing, it looks like you do (i.e. create a relatively simple information aggregator). Since this is a class, you can easily extend its functionality by adding methods.

Finally, it should be noted that class member names must be valid Python identifiers, and dictionary keys must not, so the dictionary will provide more freedom in this regard, because the keys can be hashed anything (even something that is not a string).

Update

The object class (which does not have __dict__ ) of a subclass named SimpleNamespace (which has one) was added in Python 3.3 and is another alternative.

+4
Oct 28 '10 at 21:06
source share

If all you want to achieve is syntax candy, for example obj.bla = 5 instead of obj['bla'] = 5 , especially if you need to repeat a lot, you might want to use some simple container class, as in the sentence martineaus. However, the code there is pretty bloated and unnecessarily slow. You can keep it simple:

 class AttrDict(dict): """ Syntax candy """ __getattr__ = dict.__getitem__ __setattr__ = dict.__setitem__ __delattr__ = dict.__delitem__ 

Another reason for switching to a namedtuple or class with __slots__ might be memory usage. Dictations require significantly more memory than list types, so this may be the point to think about.

In any case, in your particular case, there seems to be no motivation to abandon your current implementation. You do not seem to support millions of these objects, so the required list types are not required. And it actually contains some functional logic in __init__ , so you shouldn't have AttrDict .

+3
Sep 28
source share
 class ClassWithSlotBase: __slots__ = ('a', 'b',) def __init__(self): self.a: str = "test" self.b: float = 0.0 def test_type_hint(_b: float) -> None: print(_b) class_tmp = ClassWithSlotBase() test_type_hint(class_tmp.a) 

I recommend the class. If you use a class, you can get a type hint as shown. And class support automatically ends when the class is an argument to a function.

enter image description here

-one
Nov 27 '17 at 2:31 on
source share



All Articles