Accessing dict keys like an attribute?

前端 未结 27 2744
南笙
南笙 2020-11-22 04:22

I find it more convenient to access dict keys as obj.foo instead of obj[\'foo\'], so I wrote this snippet:

class AttributeDict(dict         


        
27条回答
  •  野的像风
    2020-11-22 05:01

    I found myself wondering what the current state of "dict keys as attr" in the python ecosystem. As several commenters have pointed out, this is probably not something you want to roll your own from scratch, as there are several pitfalls and footguns, some of them very subtle. Also, I would not recommend using Namespace as a base class, I've been down that road, it isn't pretty.

    Fortunately, there are several open source packages providing this functionality, ready to pip install! Unfortunately, there are several packages. Here is a synopsis, as of Dec 2019.

    Contenders (most recent commit to master|#commits|#contribs|coverage%):

    • addict (2019-04-28 | 217 | 22 | 100%)
    • munch (2019-12-16 | 160 | 17 | ?%)
    • easydict (2018-10-18 | 51 | 6 | ?%)
    • attrdict (2019-02-01 | 108 | 5 | 100%)
    • prodict (2019-10-01 | 65 | 1 | ?%)

    No longer maintained or under-maintained:

    • treedict (2014-03-28 | 95 | 2 | ?%)
    • bunch (2012-03-12 | 20 | 2 | ?%)
    • NeoBunch

    I currently recommend munch or addict. They have the most commits, contributors, and releases, suggesting a healthy open-source codebase for each. They have the cleanest-looking readme.md, 100% coverage, and good looking set of tests.

    I do not have a dog in this race (for now!), besides having rolled my own dict/attr code and wasted a ton of time because I was not aware of all these options :). I may contribute to addict/munch in the future as I would rather see one solid package than a bunch of fragmented ones. If you like them, contribute! In particular, looks like munch could use a codecov badge and addict could use a python version badge.

    addict pros:

    • recursive initialization (foo.a.b.c = 'bar'), dict-like arguments become addict.Dict

    addict cons:

    • shadows typing.Dict if you from addict import Dict
    • No key checking. Due to allowing recursive init, if you misspell a key, you just create a new attribute, rather than KeyError (thanks AljoSt)

    munch pros:

    • unique naming
    • built-in ser/de functions for JSON and YAML

    munch cons:

    • no recursive init / only can init one attr at a time

    Wherein I Editorialize

    Many moons ago, when I used text editors to write python, on projects with only myself or one other dev, I liked the style of dict-attrs, the ability to insert keys by just declaring foo.bar.spam = eggs. Now I work on teams, and use an IDE for everything, and I have drifted away from these sorts of data structures and dynamic typing in general, in favor of static analysis, functional techniques and type hints. I've started experimenting with this technique, subclassing Pstruct with objects of my own design:

    class  BasePstruct(dict):
        def __getattr__(self, name):
            if name in self.__slots__:
                return self[name]
            return self.__getattribute__(name)
    
        def __setattr__(self, key, value):
            if key in self.__slots__:
                self[key] = value
                return
            if key in type(self).__dict__:
                self[key] = value
                return
            raise AttributeError(
                "type object '{}' has no attribute '{}'".format(type(self).__name__, key))
    
    
    class FooPstruct(BasePstruct):
        __slots__ = ['foo', 'bar']
    
    

    This gives you an object which still behaves like a dict, but also lets you access keys like attributes, in a much more rigid fashion. The advantage here is I (or the hapless consumers of your code) know exactly what fields can and can't exist, and the IDE can autocomplete fields. Also subclassing vanilla dict means json serialization is easy. I think the next evolution in this idea would be a custom protobuf generator which emits these interfaces, and a nice knock-on is you get cross-language data structures and IPC via gRPC for nearly free.

    If you do decide to go with attr-dicts, it's essential to document what fields are expected, for your own (and your teammates') sanity.

    Feel free to edit/update this post to keep it recent!

提交回复
热议问题