class AttrDict(dict):
    """
    A dictionary that allows access to its elements as attributes.
    """

    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__init__(*args, **kwargs)

        # Recursively convert nested dictionaries to AttrDicts
        for key, value in self.items():
            if isinstance(value, dict):
                self[key] = AttrDict(value)

    def __getattr__(self, key):
        # Allow attribute access to dictionary keys
        if key in self:
            return self[key]
        raise AttributeError(f"'{type(self).__name__}' object has no attribute '{key}'")

    def __setattr__(self, key, value):
        # Allow setting dictionary keys as attributes
        self[key] = value

    def __delattr__(self, key):
        # Allow deleting dictionary keys using del
        if key in self:
            del self[key]
        else:
            raise AttributeError(f"'{type(self).__name__}' object has no attribute '{key}'")