Quantcast
Channel: How to use a dot "." to access members of dictionary? - Stack Overflow
Viewing all articles
Browse latest Browse all 40

Answer by Karolius for How to use a dot "." to access members of dictionary?

$
0
0

Here's my version of @derek73 answer. I use dict.__getitem__ as __getattr__ so it still throws KeyError, and im renaming dict public methods with "" prefix (surrounded with "" leads to special methods name conflict, like __get__ which would be treated as a descriptor method). Anyway you can't get completely clear namespace for keys as attributes due to crucial dict base methods, so the solution isn't perfect but you can have keys - attributes like get, pop, items etc.

class DotDictMeta(type):                                                              def __new__(                                                                          cls,                                                                              name,                                                                             bases,                                                                            attrs,                                                 rename_method=lambda n: f'__{n}__',                                    **custom_methods,                                                             ):                                                                                    d = dict                                                                          attrs.update(                                                                         cls.get_hidden_or_renamed_methods(rename_method),                       __getattr__=d.__getitem__,                                                        __setattr__=d.__setitem__,                                                        __delattr__=d.__delitem__,                                                        **custom_methods,                                                             )                                                                                 return super().__new__(cls, name, bases, attrs)                               def __init__(self, name, bases, attrs, **_):                                          super().__init__(name, bases, attrs)                                          @property                                                                         def attribute_error(self):                                                            raise AttributeError                                                          @classmethod                                                                      def get_hidden_or_renamed_methods(cls, rename_method=None):                          public_methods = tuple(                                                               i for i in dict.__dict__.items() if not i[0].startswith('__')                 )                                                                                 error = cls.attribute_error                                                       hidden_methods = ((k, error) for k, v in public_methods)                          yield from hidden_methods                                                         if rename_method:                                                                   renamed_methods = ((rename_method(k), v) for k, v in public_methods)             yield from renamed_methods                                             class DotDict(dict, metaclass=DotDictMeta):                                           pass  

You can remove dict methods from DotDict namespace and keep using dict class methods, its useful also when you want to operate on other dict instances and want to use the same methods without extra check whether its DotDict or not, eg.

dct = dict(a=1)dot_dct = DotDict(b=2)foo = {c: i for i, c in enumerate('xyz')}for d in (dct, dot_dct):    # you would have to use dct.update and dot_dct.__update methods    dict.update(d, foo)assert dict.get(dot, 'foo', 0) is 0

Viewing all articles
Browse latest Browse all 40

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>