4

I'd like to use a SimpleNameSpace which can also act as a mapping so to be able to be used with ** unpacking.

Here is what I've done:

class MySimpleNameSpace(object):
    # my initial attempt subclassed SimpleNameSpace and Mapping, with
    # possibility to use MySimpleNameSpace as a dict as well as a normal SimpleNameSpace.

    def __init__(self, **kw):
        self.__dict__.update(kw)

    def __getitem__(self, item):
        return getattr(self, item)

    def keys(self):
        return self.__dict__.keys()

So far so good:

def f(**kw):
    print(kw)

ns = MySimpleNameSpace(a=42)
f(**ns)

Gives: {'a': 42}

More tricky:

ns.__getitem__ = "what"
ns.__iter__ = "da"
f(**ns)

Now gives:

{'a': 42, '__getitem__': "what", '__iter__', "da" }

But:

ns.keys = "douh"
f(**ns)

Obviously gives:

TypeError: attribute of type 'str' is not callable

Any idea if this would be feasible to have such a custom mapping class but able to use keys as a normal attribute?

I realize that subclassing (Mutable)Mapping makes this actually harder, if at all possible, but I think it's all because the functionality apparently requires the given object to have a keys method, which is unfortunate if we can't find a workaround for that.

As far as I know: iterating (__iter__) a dict gives its keys, then __getitem__ gives the value associated to a given key. As far as I know this would be all enough to implement the functionality?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
gst
  • 431
  • 1
  • 4
  • 16
  • Python looks up the *"magic method"* `__getitem__` on the *class* (`ClassName.__getitem__(instance, item)`), so you can't shadow it on the instance, but looks up `keys` on the *instance itself*. `ns.__getitem__('a')` would also give a `TypeError`. – jonrsharpe Nov 05 '15 at 14:39
  • effectively for ns.\_\_getitem\_\_('a') but not ns['a'].. There would be a magic method for the "keys" method then I think my problem would also be resolved I think.. (or else the ** machinery would use \_\_iter\_\_ and \_\_getitem\_\_ that would also solves the problem I think) – gst Nov 05 '15 at 14:46
  • You should see e.g. http://stackoverflow.com/q/8601268/3001761 - `keys` is required for dictionary unpacking, so there's no way around this. I think even if you inherited `Mapping` and implemented the other methods, shadowing `keys` would break it (I haven't tried this, though). – jonrsharpe Nov 05 '15 at 14:47
  • I've for sure checked that page as well as many others.. My problem is that I'd like to be able to have absolutely no restriction on the attributes/items my custom mapping can save. More I think about it more I find that without a change at Python level on how the ** machinery behaves then nothing will workaround my problem.. but I'm unusure if that would be something valuable and/or desired .. – gst Nov 05 '15 at 14:49
  • Well you're always going to have *some* restrictions, for example you can't use invalid identifiers as attribute names except via `getattr` and `setattr`. You will just have to special-case `keys`. – jonrsharpe Nov 05 '15 at 14:50
  • 1
    *"I'm unusure if that would be something valuable and/or desired"* - and, more importantly, **how much existing code that would break** – jonrsharpe Nov 05 '15 at 14:55
  • 1
    if ** machinery would first try to use \_\_iter\_\_ and \_\_getitem\_\_ magic methods, but fallback on keys() if \_\_iter\_\_ isn't present or usable, wouldn't this achieve the solution without breaking ? without breaking most of the existing code I mean.. I think there would be cases that could break.. (thoses where \_\_iter\_\_ would gives another result than keys()) – gst Nov 05 '15 at 14:58
  • 2
    Well, *maybe*! That's the problem - there's no guarantee and you're changing something deep in the language used by thousands of programs. And the specification would need to be rigorous: should it fall back if `__iter__` can't be found, or if it raises any error, or some defined set of errors (e.g. `NotImplementedError`)? If you think this should be taken further, you might want to try the dev mailing list, it's well outside SO's scope. – jonrsharpe Nov 05 '15 at 15:00

0 Answers0