docs: def decode(rlp, sedes=None, strict=True, recursive_cache=False, **kwargs):
      """Decode an RLP encoded object.
  
      If the deserialized result `obj` has an attribute :attr:`_cached_rlp` (e.g. if `sedes` is a
      subclass of :class:`rlp.Serializable`) it will be set to `rlp`, which will improve performance
      on subsequent :func:`rlp.encode` calls. Bear in mind however that `obj` needs to make sure that
      this value is updated whenever one of its fields changes or prevent such changes entirely
      (:class:`rlp.sedes.Serializable` does the latter).
  
      :param sedes: an object implementing a function ``deserialize(code)`` which will be applied
                    after decoding, or ``None`` if no deserialization should be performed
      :param \*\*kwargs: additional keyword arguments that will be passed to the deserializer
      :param strict: if false inputs that are longer than necessary don't cause an exception
      :returns: the decoded and maybe deserialized Python object
      :raises: :exc:`rlp.DecodingError` if the input string does not end after the root item and
               `strict` is true
      :raises: :exc:`rlp.DeserializationError` if the deserialization fails
      """
      if not is_bytes(rlp):
          raise DecodingError('Can only decode RLP bytes, got type %s' % type(rlp).__name__, rlp)
      try:
          item, per_item_rlp, end = consume_item(rlp, 0)
      except IndexError:
          raise DecodingError('RLP string too short', rlp)
      if end != len(rlp) and strict:
          msg = 'RLP string ends with {} superfluous bytes'.format(len(rlp) - end)
          raise DecodingError(msg, rlp)
      if sedes:
          obj = sedes.deserialize(item, **kwargs)
          if is_sequence(obj) or hasattr(obj, '_cached_rlp'):
              _apply_rlp_cache(obj, per_item_rlp, recursive_cache)
          return obj
      else:
          return item