def __getitem__(self, key):
        """Get a component by name or index."""
        if not (isinstance(key, str) or (isinstance(key, tuple) and len(key) == 2)):
            raise KeyError('You can only access data by (data_name, component_name) tuple or data_name string.')

        # This prevents failures when this method is called in the constructor
        # self.data is not yet initialized
        actual_data = self.data if len(self.data) else (self.parent.data if self.parent else [])

        # If the key is a string, we assume it's the data name
        if isinstance(key, str):
            for data in actual_data:
                if data.name == key:
                    return data
            raise KeyError('Data {} not found.'.format(key))

        # Otherwise it's a (data name, component name) tuple
        data_name = key[0]
        component_name = key[1]

        if isinstance(data_name, str):
            for data in actual_data:
                if data.name == data_name:
                    return data[component_name]
            raise KeyError('Data {} not found.'.format(data_name))

        if isinstance(data_name, int):
            return actual_data[data_name][component_name]

        raise KeyError('Invalid key {}.'.format(key))
Get a component by name or index.
ipygany/ipygany.py