Way to mask functions on Python Object
Question: I have a class that inherit from OrderedDict, but I don't know if this is the
right way to accomplish what I need.

I would like the class to have the duel method of the javascript '.' notation
like `obj.<property>` and I would also like the users to be able to access the
class properties like `obj['myproperty']` but I was to hide all the key() and
get() functions. The inheritance model is providing good functionality, but it
cluttering up the object with additional methods that are not really needed.

Is it possible to get the dictionary behavior without all the other functions
coming along?

For this discussion, let's assume my class is this:

    
    
    from six.moves.urllib import request
    import json
    class MyClass(OrderedDict):
         def __init__(self, url):
            super(MyClass, self).__init__(url=url)
            self._url = url
            self.init()
         def init(self):
            # call the url and load the json
            req = request.Request(self._url)
            res = json.loads(request.urlopen(req).read())
            for k,v in res.items():
               setattr(self, k, v)
            self.update(res)
            self.__dict__.update(res)
    
    if __name__ == "__main__":
        url = "https://sampleserver5.arcgisonline.com/ArcGIS/rest/services?f=json"
        props = MyClass(url=url)
        props.currentVersion
    

Is there another way to approach this dilemma?

Thanks


Answer: If all you want is `x['a']` to work the same way as `x.a` without any other
functionality of dictionaries, then don't inherit from `dict` or
`OrderedDict`, instead just forward key/indice operations ([`__getitem__`,
`__setitem__` and
`__delitem__`](https://docs.python.org/3/reference/datamodel.html#object.__getitem__))
to [attribute
operations](https://docs.python.org/3/library/functions.html#getattr):

    
    
    class MyClass(object):
        def __getitem__(self,key):
            try: #change the error to a KeyError if the attribute doesn't exist
                return getattr(self,key)
            except AttributeError:
                pass
            raise KeyError(key)
    
        def __setitem__(self,key,value):
            setattr(self,key,value)
        def __delitem__(self,key):
            delattr(self,key)
    

As an added bonus, because these special methods don't check the instance
variables for the method name it doesn't break if you use the same names:

    
    
    x = MyClass()
    x['__getitem__'] = 1
    print(x.__getitem__) #still works
    print(x["__getattr__"]) #still works
    

The only time it will break is when trying to use `__dict__` since that is
where the instance variables are actually stored:

    
    
    >>> x = MyClass()
    >>> x.a = 4
    >>> x.__dict__ = 1 #stops you right away
    Traceback (most recent call last):
      File "<pyshell#36>", line 1, in <module>
        x.__dict__ = 1
    TypeError: __dict__ must be set to a dictionary, not a 'int'
    >>> x.__dict__ = {} #this is legal but removes all the previously stored values!
    >>> x.a
    Traceback (most recent call last):
      File "<pyshell#38>", line 1, in <module>
        x.a
    AttributeError: 'MyClass' object has no attribute 'a'
    

In addition you can still use the normal dictionary methods by using `vars()`:

    
    
    x = MyClass()
    x.a = 4
    x['b'] = 6
    for k,v in vars(x).items():
        print((k,v))
    
    #output
    ('b', 6)
    ('a', 4)
    >>> vars(x)
    {'b': 6, 'a': 4}
    

