I work with an embedded target that contains a list of commands and registers that may change from one device to another. So I need to build my commands list from metadata received from that particular target. 

Unfortunately, the communication with the target is slow and the amount of commands is high. So I cannot build the full command's list at the beginning, but only when somebody requests it. 

Of course, the list of commands should not be modifiable (by mistake), by the user which I assume is dumb. So I would like to prevent the instance to be easily modifiable in IPython.

For example: 

```
device = Device()
device.commands.<tab>               # the user see all the available commands
device.commands.execute = 'oops'    # I want to prevent this to happen
device.commands['execute'] = 'oops' # Neither this.

```

So I wrote this design pattern: 

```
import time

# The two following functions are the ones I use to communicate 
# with my target. 
def get_item_names():
    return ['item%d' % i for i in range(100000)]

def fetch_item(item): # Time consuming function
    time.sleep(0.1)
    return item

# The dictionary that is populated on demand.
class Foo(dict):
    __locked = False       
    def __init__(self):
        # Populate elements with None elements.
        # This is required to be able to see the available commands
        # in IPython with the auto-completion turned on.
        for item in get_item_names():
            default = None
            self[item] = default

        # This is a very ugly workaround. With cProfiler, I can see
        # the addition of __setattr__ is very costy.
        self.__locked = True

    # The item is fetched only on demand
    def __getitem__(self, item):
        if item in self and super(Foo, self).__getitem__(item) == None:
            fetched = fetch_item(item)
            super(Foo, self).__setitem__(item, fetched)
            return fetched
        else:
            return super(Foo, self).__getitem__(item)

    @property
    def __members__(self):
        return self.keys()

    def __getattr__(self, item):
        return self[item]

    def __setattr__(self, key, value):
        if self.__locked:
            print('Not possible')
        else:
            super(Foo, self).__setattr__(key, value)

    def __setitem__(self, key, value):
        if self.__locked:
            print('Not possible')
        else:
            super(Foo, self).__setitem__(key, value)

```

Is that pattern good and what can I do to improve the bad performances with the lock mechanism? I naively tried to add `setattr(self, '__setattr__', newsetattr)` to `__init__` but it does not work.