docs: def transfer(self, data):
          """Shift out `data` and return shifted in data.
  
          Args:
              data (bytes, bytearray, list): a byte array or list of 8-bit integers to shift out.
  
          Returns:
              bytes, bytearray, list: data shifted in.
  
          Raises:
              SPIError: if an I/O or OS error occurs.
              TypeError: if `data` type is invalid.
              ValueError: if data is not valid bytes.
  
          """
          if not isinstance(data, (bytes, bytearray, list)):
              raise TypeError("Invalid data type, should be bytes, bytearray, or list.")
  
          # Create mutable array
          try:
              buf = array.array('B', data)
          except OverflowError:
              raise ValueError("Invalid data bytes.")
  
          buf_addr, buf_len = buf.buffer_info()
  
          # Prepare transfer structure
          spi_xfer = _CSpiIocTransfer()
          spi_xfer.tx_buf = buf_addr
          spi_xfer.rx_buf = buf_addr
          spi_xfer.len = buf_len
  
          # Transfer
          try:
              fcntl.ioctl(self._fd, SPI._SPI_IOC_MESSAGE_1, spi_xfer)
          except OSError as e:
              raise SPIError(e.errno, "SPI transfer: " + e.strerror)
  
          # Return shifted out data with the same type as shifted in data
          if isinstance(data, bytes):
              return bytes(bytearray(buf))
          elif isinstance(data, bytearray):
              return bytearray(buf)
          elif isinstance(data, list):
              return buf.tolist()