What is Python best practice regarding dicts vs objects for easy key storage?

After some time programming in Javascript, I got a little carried away by the duality between objects and associative arrays (dictionaries):

//Javascript var stuff = { a: 17, b: 42 }; stuff.a; //direct access (good sugar for basic use) stuff['a']; //key based access (good for flexibility and for foreach loops) 

There are two ways in python to do such things (as far as I know)

Dictionaries:

 stuff = { 'a': 17, 'b':42 }; # no direct access :( stuff['a'] #key based access 

or Objects:

 #use a dummy class since instantiating object does not let me set things class O(object): pass stuff = O() stuff.a = 17 stuff.a = 42 stuff.a #direct access :) getattr(stuff, 'a') #key based access 

edit: Some answers also mention namedtuples as a way to create large classes for immutable objects.


So my questions are:

  • Are there any established best practices regarding whether I should use dicts or objects to store simple, method-free, key-values?

  • I can imagine that there are many ways to create small helper classes to make the object approach less ugly (e.g. something that gets a dict for the constructor and then overrides __getattribute__ ). Is this a good idea, or am I thinking too much about it?

    • If this is good, what would be the most enjoyable approach? Also, will there be any good Python projects using the mentioned approach from which I could breathe?
+4
source share
4 answers

Not sure about "established best practices," but I do this:

  • If the types of values โ€‹โ€‹are homogeneous, i.e. all values โ€‹โ€‹in mappings are numbers, use dict.
  • If the values โ€‹โ€‹are heterogeneous, and if there is always a given more or less constant set of keys to display, use an object. (It is preferable to use the actual class, as it smells a lot like the data type.)
  • If the values โ€‹โ€‹are heterogeneous, but the keys in the mapping change, flip the coin. I'm not sure how often this model comes up with Python, dictionaries like this one noticeably appear in Javascript for "fake" functions with keyword arguments. Python already has those, and **kwargs is a dict, so I would go with dicts.

Or, to put it another way, represent instances of data types with objects. Representation of ad-hoc or temporary comparisons with dicts. A swallow using the ['key'] syntax, making Python feel like Javascript just feels compelled for me.

+8
source

Well, if the keys are known in advance (or actually, not even, actually), you can use named tuples, which are basically easy to create with any fields that you select. The main limitation is that you must know all the keys when creating the tuple class, and they are immutable (but you can get an updated copy).

http://docs.python.org/library/collections.html#collections.namedtuple

In addition, you can almost certainly create a class that allows you to dynamically create properties.

+4
source

Well, these two approaches are closely related! When you do

 stuff.a 

you really get access to

 stulff.__dict__['a'] 

Similarly, you can subclass dict to make __getattr__ the same as __getitem__ , and so stuff.a will also work for your dict subclass.

The object approach is often convenient and useful when you know that the keys in your mapping will be all simple strings that are valid Python identifiers. If you have more complex keys, you need a "real" mapping.

Of course, you should also use objects when you need more than simple matching. This "more" will usually be an extra state or extra calculations on the return values.

You should also consider how others will use your stuff objects. If they know this is just a dict , then they also know that they can call stuff.update(other_stuff) , etc. This is not so clear if you give them back the object. Basically: if you think that they need to manipulate the keys and values โ€‹โ€‹of your stuff , like a regular dict , then you should probably make it a dict .

As for the most โ€œpythonicโ€ way to do this, I can only say that I saw that libraries use both approaches:

  • The BeautifulSoup library parses HTML and gives you very dynamic objects in which both attributes and access elements have special values.

    They could instead return dict objects, but there is a lot of extra state associated with each object, and therefore it makes sense to use a real class.

  • Of course, there are also many libraries that simply return regular dict objects โ€” these are the bread and butter of many Python programs.

+3
source

This will be the way I decide between dict and object to store simple, method-free values โ€‹โ€‹for key pairs:

  • Do I need to iterate over key pairs?
    • Yes: use dict
    • No: go to 2.
  • How many keys will I have?
    • A lot: use dict
    • Multiple: go to 3.
  • Are key names important?
    • No: use dict
    • Yes: go to 4.
  • Do I want to stone these important key names for a long time?
    • No: use dict
    • Yes: use object

It may also be interesting to look at the difference shown by dis :

 >>> def dictf(d): ... d['apple'] = 'red' ... return d['apple'] ... >>> def objf(ob): ... ob.apple = 'red' ... return ob.apple ... >>> dis.dis(dictf) 2 0 LOAD_CONST 1 ('red') 3 LOAD_FAST 0 (d) 6 LOAD_CONST 2 ('apple') 9 STORE_SUBSCR 3 10 LOAD_FAST 0 (d) 13 LOAD_CONST 2 ('apple') 16 BINARY_SUBSCR 17 RETURN_VALUE >>> dis.dis(objf) 2 0 LOAD_CONST 1 ('red') 3 LOAD_FAST 0 (ob) 6 STORE_ATTR 0 (apple) 3 9 LOAD_FAST 0 (ob) 12 LOAD_ATTR 0 (apple) 15 RETURN_VALUE 
+3
source

Source: https://habr.com/ru/post/1394768/


All Articles